Rust로 작성해 보는 컴퓨터 구조 (4) - OR 게이트

나빌레라의 이미지

AND 게이트와 마찬가지로 불리언 OR 연산 동작을 하는 OR 게이트를 트랜지스터 조합으로 만들 수 있다. 아래 표는 불리언 OR 연산의 진리표다.

입력 A 입력 B 출력
0 0 0
0 1 1
1 0 1
1 1 1

잘 알려진 OR 게이트의 트랜지스터 회로는 아래 그림과 같다.

OR 게이트

회로를 보면 입력 A나 B 둘 중 하나만 신호를 입력해도 OUT으로 출력이 나간다. 이 회로를 그대로 모델링한다.

모델링하려고 봤더니, AND 게이트와 OR 게이트는 트랜지스터 연결 방법만 다르고 구성이 같다는걸 알았다. 앞으로 나올 다른 논리 게이트들도 마찬가지다. 그래서 작업을 시작하기 전에 코드에 상속 관계를 만들어 놓으면 코드가 한결 수준 높아 진다. 리펙토링을 시작하자.

먼저 앞장에서 만든 and_gate.rs 파일의 내용을 gates.rs로 복사한다. 논리 게이트들이 공통 속성과 동작으로 묶일 것이기 때문에 코드 양이 아주 길어지지 않는한 파일 한 개에서 코드를 관리하는 것이 편하기 때문이다. 그리고 아래 코드처럼 AndGate 구조체와 Gates 구조체를 분리한다.

{caption="gates.rs | 게이트 모델 분리"}
pub struct Gates {
    pub conn_a: bool,
    pub conn_b: bool,
    pub conn_out: bool,
 
    tr1: transistor::Transistor,
    tr2: transistor::Transistor,
}
 
pub struct AndGate {
    circuit:Gates,
}

러스트는 다른 언어들처럼 클래스로 상속하는 기능이 없다. 그래서 C 언어에서 구조체를 포함하는 방식으로 코드를 작성해야 한다. 나는 이런 문법이 더 좋다. 어차피 다른 언어들도 상속을 하면 내부적으로는 러스트나 C 언어처럼 자식 클래스에서 부모 클래스의 속성을 포함하는 구조를 생성한다. 코드로 눈에 보이지 않을 뿐이다. 그럴 바에는 아예 이렇게 보이게 하는 것이 오히려 가독성이 더 좋다고 생각한다. 혹시 나중에 러스트에 클래스 문법과 다른 언어 같은 전통적인 상속 문법을 지원한다 해도 나는 위 코드같은 문법을 계속 쓸 것이다.

신호선이 세 개(A, B, OUT)고 트랜지스터 두 개를 가지고 있는 구조는 모든 논리 게이트에 공통이므로 구조체 이름을 Gates로 지었다. 그리고 AND 게이트는 Gates 구조체를 가진다. 더 생각해보면 신호선 A, B에 입력을 받아 OUT으로 결과를 출력하는 동작도 논리 게이트들의 공통점이다. 그래서 논리 게이트들이 공통으로 가지는 일종의 인터페이스 함수를 만든다.

{caption="gates.rs | 트래잇 선언"}
pub trait GateInterfaces {
    fn proc(&mut self, input_a: bool, input_b: bool) -> bool;
}
 
impl GateInterfaces for AndGate {
    fn proc(&mut self, input_a: bool, input_b: bool) -> bool {
        self.circuit.conn_a = input_a;
        self.circuit.conn_b = input_b;
 
        self.circuit.tr1.conn_c = true;
        self.circuit.tr2.conn_c = self.circuit.tr1.proc(input_a);
        self.circuit.conn_out = self.circuit.tr2.proc(input_b);
 
        return self.circuit.conn_out;
    }
}

러스트에서 trait은 다른 객체지향 언어의 인터페이스(interface)와 같은 일을 한다. 다만 차이라면 클래스와 별개라서 꼭 구현해야만 하는 것이 아니라는 점 정도다. 러스트에서 트래잇은 반드시 구현해야 하는 인터페이스라기보다 공용 인터페이스를 구조체 객체에 연결하는 개념으로 생각한다.

트래잇 GateInterfaces로 proc() 함수를 선언했다. 이 트래잇을 AndGate 구조체에 연결하면 AndGate에서 proc() 인터페이스 함수를 호출할 수 있다. 코드 내용은 앞 장에 AND 게이트 모델 구현과 같다.

이제 이 패턴 그대로 OR 게이트를 모델링한다. 아래 코드는 리펙토링 작업을 포함한 gates.rs 코드다. 앞 장의 인버터 모델 코드는 생략했다.

{caption="gates.rs | OR 게이트 모델링"}
use crate::transistor;
 
// ... 생략 ...
 
pub struct Gates {
    pub conn_a: bool,
    pub conn_b: bool,
    pub conn_out: bool,
 
    tr1: transistor::Transistor,
    tr2: transistor::Transistor,
}
 
pub struct AndGate {
    circuit:Gates,
}
 
pub struct OrGate {
    circuit:Gates,
}
 
pub trait GateInterfaces {
    fn proc(&mut self, input_a: bool, input_b: bool) -> bool;
}
 
impl Gates {
    pub fn new() -> Gates {
        Gates {
            conn_a:false,
            conn_b:false,
            conn_out:false,
            tr1:transistor::Transistor::new(),
            tr2:transistor::Transistor::new(),
        }
    }
}
 
impl AndGate {
    pub fn new() -> AndGate {
        AndGate{circuit:Gates::new()}
    }
}
 
impl OrGate {
    pub fn new() -> OrGate {
        OrGate{circuit:Gates::new()}
    }
}
 
impl GateInterfaces for AndGate {
    fn proc(&mut self, input_a: bool, input_b: bool) -> bool {
        self.circuit.conn_a = input_a;
        self.circuit.conn_b = input_b;
 
        self.circuit.tr1.conn_c = true;
        self.circuit.tr2.conn_c = self.circuit.tr1.proc(input_a);
        self.circuit.conn_out = self.circuit.tr2.proc(input_b);
 
        return self.circuit.conn_out;
    }
}
 
impl GateInterfaces for OrGate {
    fn proc(&mut self, input_a: bool, input_b: bool) -> bool {
        self.circuit.conn_a = input_a;
        self.circuit.conn_b = input_b;
 
        self.circuit.tr1.conn_c = true;
        self.circuit.tr2.conn_c = true;
 
        let temp_tr1_e = self.circuit.tr1.proc(input_a) as u8;
        let temp_tr2_e = self.circuit.tr2.proc(input_b) as u8;
        self.circuit.conn_out = (temp_tr1_e + temp_tr2_e) != 0; 
 
        return self.circuit.conn_out;
    }
}

18, 19, 20번째 줄에 OrGate 구조체를 선언했다. 코드 패턴은 AndGate 구조체와 동일하다. 왜냐하면 AND 게이트와 OR 게이트는 회로 연결에 따른 동작만 다를뿐 구조는 같기 때문이다. 26번째 줄부터 48번째 줄은 생성자 함수다. AndGate 객체와 OrGate 객체의 생성자에서 Gates 객체의 생성자를 호출한다. 50번째 줄에서 61번째 줄이 앞에서 설명한 AND 게이트의 동작을 모델링한 코드다. 63번째 줄에서 77번째 줄이 이 장의 핵심 내용인 OR 게이트의 동작을 모델링한 코드다.

OR 게이트 모델링 코드를 자세히 보겠다. OR 게이트의 트랜지스터 회로 연결을 본다. 트랜지스터 2개의 핀 C에는 기본적으로 전원이 들어간다. 그래서 68번째 줄과 69번째 줄에 tr1과 tr2 트랜지스터 객체의 conn_c 변수에 true을 입력했다. 그리고 두 트랜지스터의 출력은 하나로 합쳐져서 OUT으로 나간다. 이런식으로 전기선을 연결하면 연결된 두 선 중 하나에만 전압이 가해져도 OUT으로 전압이 출력된다. 따라서 이 것을 모델링 하려면 71, 72, 73번째 줄처럼 tr1과 tr2의 proc() 함수 결과를 더해서 0인지 비교하면 된다. 더해서 0이면 둘다 0이니까 conn_out 에는 false가 들어가고 둘 중 하나라도 1이면 0이 아니기 때문에 conn_out에는 true가 들어간다.

OR 게이트 모델 코딩은 끝냈다. 이제 테스트해보고 제대로 동작하는지 확인한다. main.rs 파일을 수정해서 불리언 OR 연산과 일치하는 결과가 나오는지 확인한다.

{caption="main.rs | OR 모델 테스트"}
mod transistor;
mod gates;
 
use gates::GateInterfaces;
 
fn main() {
//... 생략 ...
 
    let mut and_gate = gates::AndGate::new();
    println!("Test AND Gate, (0, 0) -> {}", and_gate.proc(false, false));
    println!("Test AND Gate, (0, 1) -> {}", and_gate.proc(false, true));
    println!("Test AND Gate, (1, 0) -> {}", and_gate.proc(true, false));
    println!("Test AND Gate, (1, 1) -> {}", and_gate.proc(true, true));
 
    let mut or_gate = gates::OrGate::new();
    println!("Test OR Gate, (0, 0) -> {}", or_gate.proc(false, false));
    println!("Test OR Gate, (0, 1) -> {}", or_gate.proc(false, true));
    println!("Test OR Gate, (1, 0) -> {}", or_gate.proc(true, false));
    println!("Test OR Gate, (1, 1) -> {}", or_gate.proc(true, true));
}

2번째 줄에 mod and_gate를 mod gates로 바꿨다. 파일명을 바꿨기 때문이다. 4번째 줄에 트래잇을 쓰기 위한 선언을 했다. 러스트는 트래잇을 쓰려면 이렇게 use 지시어로 트래잇을 미리 선언해야 한다. 이후 코드는 이전과 동일하여 생략했다. AND 게이트와 OR 게이트 모델 코드를 리펙토링했기 때문에 객체 선언하는 코드가 조금 바뀌었다. 바뀐 내용이 위 코드다. proc() 함수을 트래잇으로 인터페이스화했기 때문에 AND 게이트와 OR 게이트 모델 객체에서 동일한 방식으로 호출한다.

실행 결과는 다음과 같다.

Test AND Gate, (0, 0) -> false
Test AND Gate, (0, 1) -> false
Test AND Gate, (1, 0) -> false
Test AND Gate, (1, 1) -> true
Test OR Gate, (0, 0) -> false
Test OR Gate, (0, 1) -> true
Test OR Gate, (1, 0) -> true
Test OR Gate, (1, 1) -> true

결과를 보면 불리언 OR 연산과 일치하는 결과가 나왔다. 이렇게 OR 게이트 모델을 완성했다.

OR 게이트 기호

OR 게이트를 회로도에 그릴 때는 위 기호를 사용한다.

File attachments: 
첨부파일 크기
Image icon or-gate-tr.png41.69 KB
Image icon or-gate-symbol.png4.62 KB

댓글

나빌레라의 이미지

이번 편 올리면서 재미있는 놀이를 하나 했습니다.

KLDP 두루팔이 markdown을 완벽히 지원하지 못합니다. 코드를 입력할 때 markdown은 ```으로 감싸야 하지만, KLDP에는 [code] 같은 태그로 올려야 합니다. 그리고 이미지도 markdown에 있는 ![]() 문법은 동작하는데 attribute로 붙는 {width=50%} 같은건 동작을 안하죠.

문제는 제가 이 글의 원본을 markdown으로 작성했다는 것입니다. pandoc으로 손쉽게 pdf로 변환하려고 했거든요.

그러다보니 매번 올릴 때 마다 동작안하는 markdown 문법을 손으로 고쳐야 했습니다. 몇 개 안되긴 하는데 매번 손으로 찾아서 고치려니 귀찮더라구요.

그리고 이런 말도 있지않습니까. 프로그래머는 10시간 동안 할 일을 9시간 동안 코딩해서 프로그램을 만들고 59분동안 놀다가 1분동안 실행해서 해결한다.

보통 이런 일은 KLDP에 올릴 글을 따로 파일로 저장해서 python 스크립트 등을 돌리거나 awk, sed 등으로 정규표현식을 써서 해결합니다. 그런데 괜히 매번 임시 파일을 만드는게 싫더라구요.

윈도우에서는 이럴때 간단히 C# .net으로 GUI 툴 만들어서 변환한다음 마우스로 긁어서 같다 붙였습니다. 리눅스에서도 못할 건 없지요. Mono develop으로 GTK#을 쓸 수 있거든요. 처음 해 보는 거지만 해 봤습니다.

이렇게 윈도우의 visual studio랑 비슷하게 디자인합니다. 물론 GTK 기반이라 개념이 조금 다르긴 하지만 아주 오래전에 GTK 잠깐 공부했던 기억으로 GTK의 컨테이너 개념은 알고 있어서 수월하게 위젯을 배치할 수 있었습니다.

대충 코딩하고.. 코딩은 C# 이라 대충 하면 적당히 대충 돌아갑니다. C# 만세!

실행해봅니다. mono runtime이 있어야 해요. 어차피 MonoDevelop을 설치하면 mono runtime이 자동으로 설치됩니다.

이렇게 원본 텍스트를 넣고,

"변환" 버튼을 누르면 짜잔! 원하는 대로 변환된 결과가 나옵니다. 위 그림을 보면 이미지 관련이 img 태그로 바뀌었고 코드 시작에 code 태그가 들어간 것이 보입니다.

변환된 텍스트를 마우스로 긁어서 KLDP에 붙이고 이미지 올려서 경로만 바꿔주면 됩니다. 다음편부터는 조금 더 빨리 올릴 수 있겠네요.

이제 리눅스에서도 간단한 툴은 mono를 써서 위지윅 디자이너를 써서 아주 쉽게 금방 GUI로 만들어 쓸 수 있습니다.

재미 있습니다.

----------------------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.