프로젝트/Nand2Tetris
2장 프로젝트 : 가산기
cyphen156
2023. 7. 7. 15:17
2장 프로젝트에서는 가산기를 만드는 과정을 진행할 것이다.
우선 가산기(Adder)는 두 개의 n개 비트로 이루어진 숫자를 더하는 것이다.
이 가산기를 만들기 위해서는 두 개의 비트를 더해 결과를 출력하는 반 가산기와, 반가산기 2개로 구성된 전 가산기, 그리고 올림수를 처리해줄 증분기(Incrementer)가 필요하다.
1. 반 가산기
반가산기는 다음과 같이 구현된다.
bool CH02_Adder::HalfAdder(bool a, bool b, bool& sum, bool& carry)
{
// Half adder logic: sum = a XOR b, carry = a AND b
sum = CH01_boolean::Xor(a, b); // a ^ b;
carry = CH01_boolean::And(a, b); // a & b;
return true;
}
2. 전 가산기
전가산기는 다음과 같이 구현된다.
bool CH02_Adder::FullAdder(bool a, bool b, bool c, bool& sum, bool& carry)
{
// HalfAdder(c, HalfAdder(b, c, sum, carry), sum, carry)
// a ^ (b ^ c)
sum = CH01_boolean::Xor(a, CH01_boolean::Xor(b, c));
// (a & b) | (c & (a ^ b))
carry = CH01_boolean::Or(
CH01_boolean::And(a, b),
CH01_boolean::And(c, CH01_boolean::Xor(a, b)));
return true;
}
3. 증분기
증분기는 다음과 같이 구현된다. 증분기는 ++연산에 사용되는 대표적인 함수가 될 것이다.
bool CH02_Adder::Incrementer(const bool* a, bool* sum, bool& carry, int bitSize)
{
// 주어진 수에 1을 더해주는 함수
bool c = true; // 첫 자리에는 1을 더해야 하므로 초기 carry-in = true
for (int i = 0; i < bitSize; ++i) // 가변 비트 수 대응: 최대 64비트까지 대응
{
bool isSum = false, nextCarry = false;
FullAdder(a[i], false, c, isSum, nextCarry); // b=false → a + 0 + carry
sum[i] = isSum;
c = nextCarry;
}
carry = c;
return true;
}
4. 가산기
가산기는 다음과 같이 구현되었다. 증분기와 다른 점은 무조건 적인 1 증가가 아닌 b의 값에 따라 증감 여부가 결정되는 것이다.
bool CH02_Adder::Adder(const bool* a, const bool* b, bool* sum, bool& carry, int bitSize)
{
// 주어진 두 수를 더하는 함수
// incrementer에 의해 최대 비트가지 대응 가능
bool isOverFlow = false; // 오버플로우 여부를 저장하는 변수
bool c = false;
for (int i = 0; i < bitSize; ++i) // 가변 비트 수 대응: 최대 64비트까지 대응
{
bool isSum = false, nextCarry = false;
FullAdder(a[i], b[i], c, isSum, nextCarry); // b=false → a + 0 + carry
sum[i] = isSum;
c = nextCarry;
}
carry = c;
if (isOverFlow)
{
return false;
}
return true;
}
5. ALU
마지막으로 구현될 것은 ALU이다.
ALU를 위해서 많은것들이 변화했다.
ALU.h
#pragma once
class ALU
{
public:
static bool Compute(
const bool* x,
const bool* y,
bool zx,
bool nx,
bool zy,
bool ny,
bool f,
bool no,
bool* out,
bool& zr,
bool& ng,
int bitSize = 16 // 기본 16비트
);
};
ALU.cpp
아직은 기본연산으로 Add, And연산만을 지원한다.
#include "ALU.h"
#include "CH01_boolean.h"
#include "CH02_Adder.h"
bool ALU::Compute(
// 피연산자 섹터
const bool* x, const bool* y,
// 제어 신호 섹터
bool zx, bool nx, // X 피연산자 제로화, Not연산
bool zy, bool ny, // Y 피연산자 제로화, Not연산
bool f, // true면 ADD(x+y), false면 AND(x&y)
bool no, // 출력 Not연산
// 출력 섹터
bool* out, // 연산 결과
// 플래그 섹터
bool& zr, // 제로 플래그
bool& ng, // MSB 확인용
// 연산되는 비트 크기
int bitSize // (기본값: 16, 최대: 64, 최소: 1, 0은 에러)
)
{
// 0. 예외 처리 및 변수 선언
if (bitSize < 1 || bitSize > 64) // 에러: 비트 크기 범위 초과
{
return false;
}
bool _x[64] = { false }; // X 피연산자 (최대 64비트)
bool _y[64] = { false }; // Y 피연산자 (최대 64비트)
bool _out[64] = { false }; // 연산 결과 (최대 64비트)
// 1. 입력값을 zx, nx, zy, ny에 따라 전처리
for (int i = 0; i < bitSize; ++i)
{
_x[i] = x[i]; // X 피연산자 복사
_y[i] = y[i]; // Y 피연산자 복사
}
for (int i = 0; i < bitSize; ++i)
{
if (zx)
{
_x[i] = false;
}
if (nx)
{
_x[i] = CH01_boolean::Not(_x[i]);
}
if (zy)
{
_y[i] = false;
}
if (ny)
{
_y[i] = CH01_boolean::Not(_y[i]);
}
}
// 2. f에 따라 ADD 또는 AND 수행
bool carry = false;
if (f)
{
// ADD 연산 (X + Y)
CH02_Adder::Adder(_x, _y, _out, carry, bitSize);
}
else
{
// AND 연산 (X & Y)
for (int i = 0; i < bitSize; ++i)
{
_out[i] = CH01_boolean::And(_x[i], _y[i]);
}
}
// 3. no에 따라 결과를 반전
if (no)
{
for (int i = 0; i < bitSize; ++i)
{
_out[i] = CH01_boolean::Not(_out[i]);
}
}
// 4. 결과를 out[]에 저장
for (int i = 0; i < bitSize; ++i)
{
out[i] = _out[i];
}
// 5. zr, ng 플래그 계산 및 반환
zr = true;
for (int i = 0; i < bitSize; ++i)
{
if (out[i])
{
zr = false;
break;
}
}
ng = out[bitSize - 1];
return true;
}
Resource.h
// ALU 연산 그룹
#define ID_EDIT_ALU_X 2001
#define ID_EDIT_ALU_Y 2002
#define ID_ALU_ZX 2003
#define ID_ALU_NX 2004
#define ID_ALU_ZY 2005
#define ID_ALU_NY 2006
#define ID_ALU_F 2007
#define ID_ALU_NO 2008
#define ID_BTN_ALU_EXEC 2009
#define ID_STATIC_ALU_OUT 2010
Nand2Tetris.cpp
CASE WM_CREATE:
// ----------------------------
// ALU 입력/제어 입력 라인 (하단)
// ----------------------------
// ALU 입력 텍스트 박스: X
CreateWindowW(L"static", L"X 입력:", WS_CHILD | WS_VISIBLE, 20, 360, 60, 25, hWnd, NULL, hInst, NULL);
CreateWindowW(L"edit", L"", WS_CHILD | WS_VISIBLE | WS_BORDER, 80, 360, 200, 25, hWnd, (HMENU)ID_EDIT_ALU_X, hInst, NULL);
// ALU 입력 텍스트 박스: Y
CreateWindowW(L"static", L"Y 입력:", WS_CHILD | WS_VISIBLE, 20, 400, 60, 25, hWnd, NULL, hInst, NULL);
CreateWindowW(L"edit", L"", WS_CHILD | WS_VISIBLE | WS_BORDER, 80, 400, 200, 25, hWnd, (HMENU)ID_EDIT_ALU_Y, hInst, NULL);
// ALU 제어 신호 버튼들 (토글 방식)
CreateWindowW(L"button", L"ZX", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, 300, 360, 60, 25, hWnd, (HMENU)ID_ALU_ZX, hInst, NULL);
CreateWindowW(L"button", L"NX", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, 360, 360, 60, 25, hWnd, (HMENU)ID_ALU_NX, hInst, NULL);
CreateWindowW(L"button", L"ZY", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, 420, 360, 60, 25, hWnd, (HMENU)ID_ALU_ZY, hInst, NULL);
CreateWindowW(L"button", L"NY", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, 480, 360, 60, 25, hWnd, (HMENU)ID_ALU_NY, hInst, NULL);
CreateWindowW(L"button", L"F", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, 540, 360, 60, 25, hWnd, (HMENU)ID_ALU_F, hInst, NULL);
CreateWindowW(L"button", L"NO", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, 600, 360, 60, 25, hWnd, (HMENU)ID_ALU_NO, hInst, NULL);
// ALU 실행 버튼
CreateWindowW(L"button", L"ALU 계산", WS_CHILD | WS_VISIBLE, 300, 400, 120, 30, hWnd, (HMENU)ID_BTN_ALU_EXEC, hInst, NULL);
// ALU 결과 출력 Static
CreateWindowW(L"static", L"ALU 출력:", WS_CHILD | WS_VISIBLE, 20, 440, 100, 25, hWnd, NULL, hInst, NULL);
CreateWindowW(L"static", L"", WS_CHILD | WS_VISIBLE | WS_BORDER, 120, 440, 400, 25, hWnd, (HMENU)ID_STATIC_ALU_OUT, hInst, NULL);
CASE WM_COMMAND:
case ID_BTN_ALU_EXEC:
{
wchar_t bufX[65] = { 0 };
wchar_t bufY[65] = { 0 };
GetWindowText(GetDlgItem(hWnd, ID_EDIT_ALU_X), bufX, 65);
GetWindowText(GetDlgItem(hWnd, ID_EDIT_ALU_Y), bufY, 65);
int lenX = wcslen(bufX);
int lenY = wcslen(bufY);
int bitSize = max(lenX, lenY);
if (bitSize < 1 || bitSize > 64)
{
MessageBox(hWnd, L"입력 비트 수는 1~64 사이여야 합니다.", L"오류", MB_OK | MB_ICONERROR);
break;
}
bool x[64] = { false };
bool y[64] = { false };
bool out[64] = { false };
bool zr = false;
bool ng = false;
// 입력 비트 문자열을 오른쪽 정렬하여 배열로 변환 (LSB가 인덱스 0)
for (int i = 0; i < bitSize; ++i)
{
if (i < lenX)
x[i] = (bufX[lenX - 1 - i] == L'1');
if (i < lenY)
y[i] = (bufY[lenY - 1 - i] == L'1');
}
// 제어 비트 확인
bool zx = (SendMessage(GetDlgItem(hWnd, ID_ALU_ZX), BM_GETCHECK, 0, 0) == BST_CHECKED);
bool nx = (SendMessage(GetDlgItem(hWnd, ID_ALU_NX), BM_GETCHECK, 0, 0) == BST_CHECKED);
bool zy = (SendMessage(GetDlgItem(hWnd, ID_ALU_ZY), BM_GETCHECK, 0, 0) == BST_CHECKED);
bool ny = (SendMessage(GetDlgItem(hWnd, ID_ALU_NY), BM_GETCHECK, 0, 0) == BST_CHECKED);
bool f = (SendMessage(GetDlgItem(hWnd, ID_ALU_F), BM_GETCHECK, 0, 0) == BST_CHECKED);
bool no = (SendMessage(GetDlgItem(hWnd, ID_ALU_NO), BM_GETCHECK, 0, 0) == BST_CHECKED);
if (!ALU::Compute(x, y, zx, nx, zy, ny, f, no, out, zr, ng, bitSize))
{
MessageBox(hWnd, L"ALU 연산 실패", L"에러", MB_OK | MB_ICONERROR);
break;
}
// 결과를 문자열로 변환
wchar_t result[65] = { 0 };
for (int i = 0; i < bitSize; ++i)
{
result[bitSize - 1 - i] = out[i] ? L'1' : L'0';
}
// 결과 출력
SetWindowText(GetDlgItem(hWnd, ID_STATIC_ALU_OUT), result);
}
최종 코드는 다음과 같습니다.
Nand2Tetris.cpp
// Nand2Tetris.cpp : 애플리케이션에 대한 진입점을 정의합니다.
//
#include "framework.h"
#include "Nand2Tetris.h"
#include "CH01_boolean.h"
#include "ALU.h"
#define MAX_LOADSTRING 100
// 전역 변수:
HINSTANCE hInst; // 현재 인스턴스입니다.
WCHAR szTitle[MAX_LOADSTRING]; // 제목 표시줄 텍스트입니다.
WCHAR szWindowClass[MAX_LOADSTRING]; // 기본 창 클래스 이름입니다.
// 커스텀 변수를 정의합니다.
bool inputA = false;
bool inputB = false;
bool result = false;
bool inputSel = false;
bool result_or = false;
bool result_not = false;
bool result_xor = false;
bool result_nor = false;
bool result_nand = false;
bool result_mux = false;
bool result_demux_a = false;
bool result_demux_b = false;
// 이 코드 모듈에 포함된 함수의 선언을 전달합니다:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: 여기에 코드를 입력합니다.
// 전역 문자열을 초기화합니다.
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_NAND2TETRIS, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// 애플리케이션 초기화를 수행합니다:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_NAND2TETRIS));
MSG msg;
// 기본 메시지 루프입니다:
while (1)
{
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
break;
}
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else
{
// 메시지가 없을 때 수행할 작업이 있다면 여기에 작성합니다.
// 예: 애니메이션 업데이트, 게임 루프 등
}
}
return (int) msg.wParam;
}
//
// 함수: MyRegisterClass()
//
// 용도: 창 클래스를 등록합니다.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_NAND2TETRIS));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_NAND2TETRIS);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
//
// 함수: InitInstance(HINSTANCE, int)
//
// 용도: 인스턴스 핸들을 저장하고 주 창을 만듭니다.
//
// 주석:
//
// 이 함수를 통해 인스턴스 핸들을 전역 변수에 저장하고
// 주 프로그램 창을 만든 다음 표시합니다.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // 인스턴스 핸들을 전역 변수에 저장합니다.
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// 함수: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// 용도: 주 창의 메시지를 처리합니다.
//
// WM_COMMAND - 애플리케이션 메뉴를 처리합니다.
// WM_PAINT - 주 창을 그립니다.
// WM_DESTROY - 종료 메시지를 게시하고 반환합니다.
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
// 입력 버튼
CreateWindowW(L"button", L"A : 0", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 20, 20, 100, 25, hWnd, (HMENU)ID_BTN_INPUT_A, hInst, NULL);
CreateWindowW(L"button", L"B : 0", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 20, 60, 100, 25, hWnd, (HMENU)ID_BTN_INPUT_B, hInst, NULL);
CreateWindowW(L"button", L"SEL = 0", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 20, 100, 100, 25, hWnd, (HMENU)ID_BTN_SEL_TOGGLE, hInst, NULL);
// 연산 버튼
CreateWindowW(L"button", L"AND", WS_CHILD | WS_VISIBLE, 140, 20, 240, 25, hWnd, (HMENU)ID_BTN_AND, hInst, NULL);
CreateWindowW(L"button", L"OR", WS_CHILD | WS_VISIBLE, 140, 60, 240, 25, hWnd, (HMENU)ID_BTN_OR, hInst, NULL);
CreateWindowW(L"button", L"NOT(A)", WS_CHILD | WS_VISIBLE, 140, 100, 240, 25, hWnd, (HMENU)ID_BTN_NOT, hInst, NULL);
CreateWindowW(L"button", L"XOR", WS_CHILD | WS_VISIBLE, 140, 140, 240, 25, hWnd, (HMENU)ID_BTN_XOR, hInst, NULL);
CreateWindowW(L"button", L"NOR", WS_CHILD | WS_VISIBLE, 140, 180, 240, 25, hWnd, (HMENU)ID_BTN_NOR, hInst, NULL);
CreateWindowW(L"button", L"NAND", WS_CHILD | WS_VISIBLE, 140, 220, 240, 25, hWnd, (HMENU)ID_BTN_NAND, hInst, NULL);
CreateWindowW(L"button", L"MUX", WS_CHILD | WS_VISIBLE, 140, 260, 240, 25, hWnd, (HMENU)ID_BTN_MUX, hInst, NULL);
CreateWindowW(L"button", L"DEMUX", WS_CHILD | WS_VISIBLE, 140, 300, 240, 25, hWnd, (HMENU)ID_BTN_DEMUX, hInst, NULL);
// 출력 Static
CreateWindowW(L"static", L"출력", WS_CHILD | WS_VISIBLE, 420, 20, 200, 25, hWnd, (HMENU)ID_STATIC_OUTPUT, hInst, NULL);
CreateWindowW(L"static", L"MUX 결과", WS_CHILD | WS_VISIBLE, 420, 60, 200, 25, hWnd, (HMENU)ID_STATIC_MUX_OUTPUT, hInst, NULL);
CreateWindowW(L"static", L"DEMUX A", WS_CHILD | WS_VISIBLE, 420, 100, 200, 25, hWnd, (HMENU)ID_STATIC_DEMUX_A, hInst, NULL);
CreateWindowW(L"static", L"DEMUX B", WS_CHILD | WS_VISIBLE, 420, 140, 200, 25, hWnd, (HMENU)ID_STATIC_DEMUX_B, hInst, NULL);
// ----------------------------
// ALU 입력/제어 입력 라인 (하단)
// ----------------------------
// ALU 입력 텍스트 박스: X
CreateWindowW(L"static", L"X 입력:", WS_CHILD | WS_VISIBLE, 20, 360, 60, 25, hWnd, NULL, hInst, NULL);
CreateWindowW(L"edit", L"", WS_CHILD | WS_VISIBLE | WS_BORDER, 80, 360, 200, 25, hWnd, (HMENU)ID_EDIT_ALU_X, hInst, NULL);
// ALU 입력 텍스트 박스: Y
CreateWindowW(L"static", L"Y 입력:", WS_CHILD | WS_VISIBLE, 20, 400, 60, 25, hWnd, NULL, hInst, NULL);
CreateWindowW(L"edit", L"", WS_CHILD | WS_VISIBLE | WS_BORDER, 80, 400, 200, 25, hWnd, (HMENU)ID_EDIT_ALU_Y, hInst, NULL);
// ALU 제어 신호 버튼들 (토글 방식)
CreateWindowW(L"button", L"ZX", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, 300, 360, 60, 25, hWnd, (HMENU)ID_ALU_ZX, hInst, NULL);
CreateWindowW(L"button", L"NX", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, 360, 360, 60, 25, hWnd, (HMENU)ID_ALU_NX, hInst, NULL);
CreateWindowW(L"button", L"ZY", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, 420, 360, 60, 25, hWnd, (HMENU)ID_ALU_ZY, hInst, NULL);
CreateWindowW(L"button", L"NY", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, 480, 360, 60, 25, hWnd, (HMENU)ID_ALU_NY, hInst, NULL);
CreateWindowW(L"button", L"F", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, 540, 360, 60, 25, hWnd, (HMENU)ID_ALU_F, hInst, NULL);
CreateWindowW(L"button", L"NO", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, 600, 360, 60, 25, hWnd, (HMENU)ID_ALU_NO, hInst, NULL);
// ALU 실행 버튼
CreateWindowW(L"button", L"ALU 계산", WS_CHILD | WS_VISIBLE, 300, 400, 120, 30, hWnd, (HMENU)ID_BTN_ALU_EXEC, hInst, NULL);
// ALU 결과 출력 Static
CreateWindowW(L"static", L"ALU 출력:", WS_CHILD | WS_VISIBLE, 20, 440, 100, 25, hWnd, NULL, hInst, NULL);
CreateWindowW(L"static", L"", WS_CHILD | WS_VISIBLE | WS_BORDER, 120, 440, 400, 25, hWnd, (HMENU)ID_STATIC_ALU_OUT, hInst, NULL);
break;
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// 메뉴 선택을 구문 분석합니다:
switch (wmId)
{
case ID_BTN_INPUT_A:
inputA = !inputA;
SetWindowText(GetDlgItem(hWnd, ID_BTN_INPUT_A), inputA ? L"A : 1" : L"A : 0");
break;
case ID_BTN_INPUT_B:
inputB = !inputB;
SetWindowText(GetDlgItem(hWnd, ID_BTN_INPUT_B), inputB ? L"B : 1" : L"B : 0");
break;
case ID_BTN_SEL_TOGGLE:
inputSel = !inputSel;
SetWindowText(GetDlgItem(hWnd, ID_BTN_SEL_TOGGLE), inputSel ? L"SEL=A" : L"SEL=B");
break;
case ID_BTN_AND:
result = CH01_boolean::And(inputA, inputB);
SetWindowText(GetDlgItem(hWnd, ID_STATIC_OUTPUT), result ? L"AND = 1" : L"AND = 0");
break;
case ID_BTN_OR:
result_or = CH01_boolean::Or(inputA, inputB);
SetWindowText(GetDlgItem(hWnd, ID_STATIC_OUTPUT), result_or ? L"OR = 1" : L"OR = 0");
break;
case ID_BTN_NOT:
result_not = CH01_boolean::Not(inputA);
SetWindowText(GetDlgItem(hWnd, ID_STATIC_OUTPUT), result_not ? L"NOT(A) = 1" : L"NOT(A) = 0");
break;
case ID_BTN_XOR:
result_xor = CH01_boolean::Xor(inputA, inputB);
SetWindowText(GetDlgItem(hWnd, ID_STATIC_OUTPUT), result_xor ? L"XOR = 1" : L"XOR = 0");
break;
case ID_BTN_NOR:
result_nor = CH01_boolean::Nor(inputA, inputB);
SetWindowText(GetDlgItem(hWnd, ID_STATIC_OUTPUT), result_nor ? L"NOR = 1" : L"NOR = 0");
break;
case ID_BTN_NAND:
result_nand = CH01_boolean::Nand(inputA, inputB);
SetWindowText(GetDlgItem(hWnd, ID_STATIC_OUTPUT), result_nand ? L"NAND = 1" : L"NAND = 0");
break;
case ID_BTN_MUX:
result_mux = CH01_boolean::MUX(inputA, inputB, inputSel);
SetWindowText(GetDlgItem(hWnd, ID_STATIC_MUX_OUTPUT), result_mux ? L"MUX = 1" : L"MUX = 0");
break;
case ID_BTN_DEMUX:
CH01_boolean::Demux(inputA, inputSel, result_demux_a, result_demux_b);
SetWindowText(GetDlgItem(hWnd, ID_STATIC_DEMUX_A), result_demux_a ? L"DEMUX A = 1" : L"DEMUX A = 0");
SetWindowText(GetDlgItem(hWnd, ID_STATIC_DEMUX_B), result_demux_b ? L"DEMUX B = 1" : L"DEMUX B = 0");
break;
case ID_BTN_ALU_EXEC:
{
wchar_t bufX[65] = { 0 };
wchar_t bufY[65] = { 0 };
GetWindowText(GetDlgItem(hWnd, ID_EDIT_ALU_X), bufX, 65);
GetWindowText(GetDlgItem(hWnd, ID_EDIT_ALU_Y), bufY, 65);
int lenX = wcslen(bufX);
int lenY = wcslen(bufY);
int bitSize = max(lenX, lenY);
if (bitSize < 1 || bitSize > 64)
{
MessageBox(hWnd, L"입력 비트 수는 1~64 사이여야 합니다.", L"오류", MB_OK | MB_ICONERROR);
break;
}
bool x[64] = { false };
bool y[64] = { false };
bool out[64] = { false };
bool zr = false;
bool ng = false;
// 입력 비트 문자열을 오른쪽 정렬하여 배열로 변환 (LSB가 인덱스 0)
for (int i = 0; i < bitSize; ++i)
{
if (i < lenX)
x[i] = (bufX[lenX - 1 - i] == L'1');
if (i < lenY)
y[i] = (bufY[lenY - 1 - i] == L'1');
}
// 제어 비트 확인
bool zx = (SendMessage(GetDlgItem(hWnd, ID_ALU_ZX), BM_GETCHECK, 0, 0) == BST_CHECKED);
bool nx = (SendMessage(GetDlgItem(hWnd, ID_ALU_NX), BM_GETCHECK, 0, 0) == BST_CHECKED);
bool zy = (SendMessage(GetDlgItem(hWnd, ID_ALU_ZY), BM_GETCHECK, 0, 0) == BST_CHECKED);
bool ny = (SendMessage(GetDlgItem(hWnd, ID_ALU_NY), BM_GETCHECK, 0, 0) == BST_CHECKED);
bool f = (SendMessage(GetDlgItem(hWnd, ID_ALU_F), BM_GETCHECK, 0, 0) == BST_CHECKED);
bool no = (SendMessage(GetDlgItem(hWnd, ID_ALU_NO), BM_GETCHECK, 0, 0) == BST_CHECKED);
if (!ALU::Compute(x, y, zx, nx, zy, ny, f, no, out, zr, ng, bitSize))
{
MessageBox(hWnd, L"ALU 연산 실패", L"에러", MB_OK | MB_ICONERROR);
break;
}
// 결과를 문자열로 변환
wchar_t result[65] = { 0 };
for (int i = 0; i < bitSize; ++i)
{
result[bitSize - 1 - i] = out[i] ? L'1' : L'0';
}
// 결과 출력
SetWindowText(GetDlgItem(hWnd, ID_STATIC_ALU_OUT), result);
}
break;
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: 여기에 hdc를 사용하는 그리기 코드를 추가합니다...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// 정보 대화 상자의 메시지 처리기입니다.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
//모든 자료들은 Nand2Tetris홈페이지에서 찾을 수 있습니다.
또는 다음 주소에서 찾으실 수 있습니다.
https://github.com/cyphen156/Nand2Tetris
GitHub - cyphen156/Nand2Tetris: 운영체제 공부용
운영체제 공부용. Contribute to cyphen156/Nand2Tetris development by creating an account on GitHub.
github.com