아주 작고 단순한 VM의 설계.

나빌레라의 이미지

llvm이나 jvm을 사용하고 싶었으나, 머리가 나빠서 당최 이해 하질 못해 그냥 VM 아키텍처(라지만 그냥 명령어 셋)를 만들기로 결정했습니다.

그래봐야 ARM 명령어와 학교때 시스템 프로그래밍 교재에 나왔던 sic/xe VM의 명령어 구조를 적절히 조합해서 섞은 수준밖에 되지 않습니다. 그나마도 거기서 스펙을 아주 아주 줄였죠...-_-;

그러다 보니 VM이 제공하는 기능은 매우 협소해졌고 대신 단순하기 때문에 이해하기는 쉬워졌습니다.

문제는 그 단순함으로 인해 꼭 필요하지만 할 수 없는 것들이 생겨버린다는 겁니다.
(꼭 필요하진 않지만 있으면 좋은것들은 왠만하면 하지 않을 생각입니다.^^)

VM 명령어를 설계하고 몇주간 혼자 이리저리 생각해 봤지만 제 능력으로는 더이상 뭘 발견하기 어려워 KLDP에 올려봅니다.

--- 여기 부터 ---

명령어의 길이는 32bit고정
SMP나 pipe line은 고려하지 않음
자료형 역시 1워드로 고정

레지스터

  • 4bit로 표현 : 총 16개 제공
  • 각 레지스터의 크기는 당연히 32bit
  • 범용레지스터 : 12개 (A~L)
  • 특수레지스터 : 3개
    • PC - Program Counter
    • LR - Link Register
    • SP - Stack Pointer
  • 상태레지스터 : 1개 - ST
  • 각 비트별로 사용 4개 정의 28비트 예약
    • Overflow - STO
    • Carry - STC
    • Zero - STZ
    • Negative - STN

명령어

  • 5bit로 표현 : 최대 32개
  • +1bit : 레지스터/값 선택비트 - 이 값이 0이면 마지막 인자는 레지스터, 1이면 값 혹은 주소.
  • 그래서 5+1bit : 64개.
  • value나 address에 할당된 비트보다 큰 값이 코딩으로 들어오면 어셈블러에서 mov와 add명령으로 레지스터에 넣은다음 처리
  • 주소지정 방식은 무조건 직접주소지정(direct indexing)만 사용한다.
  • 데이터 처리 명령어
    • 이동
      • MOV Rd, [Rs | #Value] ; Rs의 값이나 Value를 Rd에 저장
    • 산술
      • ADD Rd, R1, [R2 | #Value] ; R1의 값과 (R2의값 혹은 Value)를 더해서 Rd에 저장
      • SUB Rd, R1, [R2 | #Value] ; R1의 값과 (R2의값 혹은 Value)를 빼서 Rd에 저장
      • MUL Rd, R1, [R2 | #Value] ; R1의 값과 (R2의값 혹은 Value)를 곱해서 Rd에 저장
      • DIV Rd, R1, [R2 | #Value] ; R1의 값과 (R2의값 혹은 Value)를 나눠서 Rd에 저장
      • MOD Rd, R1, [R2 | #Value] ; R1의 값과 (R2의값 혹은 Value)를 나눠서 나머지를 Rd에 저장
    • 비교
      • CMP R1, [R2 | #Value] ; R1의 값과 (R2의값 혹은 Value)를 비교, 같으면 STZ=1, 작으면 STN=1이 된다. (사실상 빼기와 같다)
    • 논리
      • AND Rd, R1, [R2 | #Value] ; R1의 값과 (R2의값 혹은 Value)를 논리and 연산해서 Rd에 저장
      • OR Rd, R1, [R2 | #Value] ; R1의 값과 (R2의값 혹은 Value)를 논리or 연산해서 Rd에 저장
      • XOR Rd, R1, [R2 | #Value] ; R1의 값과 (R2의값 혹은 Value)를 논리xor 연산해서 Rd에 저장
    • 비트시프트
      • SHL Rd, [Rc | #Value] ; Rd의 값을 (Rc의값 혹은 Value)만큼 왼쪽 비트 시프트
      • SHR Rd, [Rc | #Value] ; Rd의 값을 (Rc의값 혹은 Value)만큼 오른쪽 비트 시프트
  • 분기 명령어
    • BR [Reg | #Address] ; Reg의 값 혹은 Address가 가리키는 주소로 무조건 점프
    • BSUB [Reg | #Address] ; Reg의 값 혹은 Address가 가리키는 주소로 점프하면서 자동으로 LR = PC + 4를 해 준다. (서브루틴 점프용)
    • BEQ [Reg | #Address] ; STZ == 1 이면 Reg의 값 혹은 Address가 가리키는 주소로 점프
    • BGT [Reg | #Address] ; (STZ == 0 && STN == 0) 이면 Reg의 값 혹은 Address가 가리키는 주소로 점프
    • BLT [Reg | #Address] ; (STZ == 0 && STN == 1) 이면 Reg의 값 혹은 Address가 가리키는 주소로 점프
    • BGET [Reg | #Address] ; (STZ == 1 || STN == 0) 이면 Reg의 값 혹은 Address가 가리키는 주소로 점프
    • BLET [Reg | #Address] ; (STZ == 1 || STN == 1) 이면 Reg의 값 혹은 Address가 가리키는 주소로 점프
  • 메모리 명령어
    • 한 레지스터 메모리 처리 명령어
      • LDR Rd, [Rs | #Address] ; Rs의 값 혹은 Address가 가리키는 주소에 있는 값을 Rd에 저장
      • STR Rd, [Rs | #Address] ; Rd의 값을 Rs의 값 혹은 Address가 가리키는 주소에 저장
    • 여러 레지스터 메모리 처리 명령어
      • LDM Reg{!}, <Reg1, Reg2, ..., RegN> ; Reg 주소부터 32비트씩 읽어서 Reg1, Reg2, ... RegN에 각각 저장, Reg!로 지정하면 하나씩 저장할때 마다 Reg+=4
      • STM Reg{!}, <Reg1, Reg2, ..., RegN> ; Reg1, Reg2, ... RegN의 값을 하나씩 읽으면서 Reg주소부터 32비트씩 저장, Reg!로 지정하면 할때마다 Reg+=4
  • VM 시스템 콜
    • OPT syscall, parameter ; syscall번호의 VM 시스템콜을 수행한다.
      • 0x01 - 화면에 parameter를 쓴다. parameter는 레지스터. 레지스터의 값을 화면에 뿌린다.
      • 0x02 - 키보드로 부터 32비트를 읽는다. parameter는 레지스터. 키보드로 부터 읽은 32비트 값을 레지스터에 저장한다.
      • 0xFF - Exit. Parameter는 레지스터, 값이 리턴값이다.

각 명령별 비트 할당

명령어의 기계어 코드 배정

  • MOV 0x01
  • ADD 0x02
  • SUB 0x03
  • MUL 0x04
  • DIV 0x05
  • MOD 0x06
  • CMP 0x07
  • AND 0x08
  • OR 0x09
  • XOR 0x0A
  • SHL 0x0B
  • SHR 0x0C
  • B 0x0D
  • BSUB 0x0E
  • BEQ 0x0F
  • BGT 0x10
  • BLT 0x11
  • BGET 0x12
  • BLET 0x13
  • LDR 0x14
  • STR 0x15
  • LDM 0x16
  • STM 0x17
  • OPT 0x18
  • 0x19~0x1F 까지 예약

레지스터의 기계어 배정

  • ST 0x0
  • A 0x1
  • B 0x2
  • C 0x3
  • D 0x4
  • E 0x5
  • F 0x6
  • G 0x7
  • H 0x8
  • I 0x9
  • J 0xA
  • K 0xB
  • L 0xC
  • PC 0xD
  • LR 0xE
  • SP 0xF
File attachments: 
첨부파일 크기
Image icon opcode_bit.png48.38 KB

댓글

vacancy의 이미지


VM을 이용해서 binary만 돌리시려는 거라면
instruction set은 기존의 것들 중에 고르시면 어떨까요 ?
( 디코딩하기 좋은 MIPS도 좋겠네요 .. )
VM을 만드시는 데 드는 비용을 많이 줄이실 수 있으실듯 합니다.
Qemu 등 좋은 에뮬레이터들이 많이 있으니까요.

만드시려는 컴파일러에서 바이너리를 바로 생성하실게 아니라면
기존 instruction set에 맞게 어셈블리 코드를 생성해주면
이미 있는 툴들의 도움을 많이 얻으실 수 있을 것 같습니다.
링커나 디버거를 공짜로 얻는 셈이니까요.

사실 재미로 하시려는 부분이 frontend인지 backend인지에 따라
크게 방향이 좌우되실것 같은데요. ^^;
Frontend쪽이시라면 기존것을 많이 쓰시는 편이 좋을듯합니다.

iolo의 이미지

http://en.wikipedia.org/wiki/Stack_machine

모든 현대적인 마이크로 VM의 원형이라고 할 수 있는 stack machine을 참조해보세요.
관련 자료들 링크도 많이 있네요~

----
the smile has left your eyes...

----
the smile has left your eyes...

clique의 이미지

SIC/XE... orz 추억이 보글보글

gurugio의 이미지


몇년 후면 나빌레라님 이름으로
드래곤북이 나올것 같습니다.
화이팅~~

----
섬기며 사랑하면 더 행복해집니다.
개인 홈페이지가 생겼습니다 http://caoskernel.org
어셈러브를 개편중입니다 http://www.asmlove.co.kr

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.