PRISM

ซีพียู PRISM (Primitive Stack Machine) เป็น stack machine เนื่องจากคำสั่งของซีพียูนี้จะกระทำกับสแตค (stack) เช่น คำสั่ง add จะ pop ข้อมูลออกจากสแตคสองครั้ง, นำสองค่านั้นมาบวกกัน, นำผลลัพธ์ push กลับลงไปที่สแตค

PRISM มี register 3 ตัว โปรแกรมเมอร์ไม่สามารถแก้ไขค่าของ register ได้โดยตรง ซึ่งต่างจากซีพียูทั่วไปที่จะมี register อยู่จำนวนหนึ่งที่โปรแกรมเมอร์สามารถกำหนดค่าได้โดยตรง

  • sp (stack pointer) ชี้เหนือชั้นบนสุดของสแตค
  • pc (program counter) ชี้ไปที่เป็นคำสั่งที่จะประมวลผล อีกครั้งที่ซีพียูนี้ต่างกับซีพียูทั่วไป เนื่องจากมีแรม (RAM) สองส่วน คือส่วนที่ใช้เก็บโค้ด และส่วนที่เป็นสแตค โดยแต่ละ address จะเก็บข้อมูลขนาด 32 บิท ทั้งนี้เพื่อความง่ายในการเขียนคอมไพเลอร์และ emulator
  • fp (frame pointer)

PRISM รู้จักคำสั่ง 16 คำสั่ง แบ่งออกเป็นกลุ่มๆดังนี้

  • pim (push immediate) จะนำ operand ไป push ลงสแตค เช่น ถ้าในสแตคมีเลข 2 แล้วเราสั่งว่า pim 5 สแตคก็จะมีเลข 2, 5 โดยที่ 5 จะอยู่ด้านบนสุดของสแตค
  • pop จะนำค่าบนสุดของสแตคทิ้งไป
  • คณิตศาสตร์ add, sub, mul, div สำหรับ บวก, ลบ, คูณ, และหาร เลขจำนวนเต็มขนาด 32 บิท การทำงานของคำสั่งเหล่านี้เป็นตามที่ได้อธิบายไปแล้ว
  • ตรรกะ and, or, not สำหรับตัวดำเนินการแบบบิต AND, OR, และ NOT โดยการ AND และ OR เป็นการดำเนินการเชิงตรรกะที่รับสองค่า (ได้จากการ pop) สำหรับการ not จะ pop แค่ครั้งเดียว ถ้าเป็น 0 จะ push(-1) แต่ถ้า pop ได้เลขอื่นๆ จะ push(0) กลับลงสแตค
  • ldp (load and push) และ sto (store) ldp ใช้สำหรับอ่านค่าจาก stack โดยจะ pop offset, อ่านค่าจากตำแหน่ง fp + offset, แล้ว push ค่าที่อ่านมานั้นลงสแตค สำหรับคำสั่ง sto ใช้เขียนค่าลง stack โดยจาก pop offset, pop ค่าที่จะเขียน, แล้วเขียนค่าไปยังตำแหน่ง fp + offset
  • jng (jump if negative) จะ pop แล้วดู sign bit ถ้าเป็น 1 (เลขลบ) จะ go to เลเบลที่กำหนด
  • prn (print) มีการทำงานคือ pop แล้วพิมพ์ค่า คำสั่งนี้เป็นคำสั่งระดับสูง ไม่มีให้ใช้ซีพียูปรกติ
  • hlt (halt) หยุดการทำงานของโปรแกรม
  • cll (call) และ ret เกี่ยวกับฟังก์ชัน

หากจะนำข้อความหรือโค้ดไปใช้ ต้องแสดงที่มา และห้ามใช้ในเชิงพาณิชย์

โค้ด emulator เป็นดังนี้

import java.io.*;

public class Prism {

  public static final int PIM = 0;
  public static final int JNG = 1;
  public static final int CLL = 2;
  public static final int POP = 3;
  public static final int STO = 4;
  public static final int LDP = 5;
  public static final int ADD = 6;
  public static final int SUB = 7;
  public static final int MUL = 8;
  public static final int DIV = 9;
  public static final int AND = 10;
  public static final int OR = 11;
  public static final int NOT = 12;
  public static final int RET = 13;
  public static final int PRN = 14;
  public static final int HLT = 15;

  int[] code = new int[1024]; // 1k of code
  int pc; // program counter

  int[] stack = new int[1024]; // 1k of data
  int sp; // stack pointer
  int fp; // frame pointer

  public static void main(String[] args) throws Exception {
    new Prism().run(args[0], args.length == 2);
  }

  void push(int n) {
    stack[sp++] = n;
  }

  int pop() {
    return stack[--sp];
  }

  void printStack() {
    System.out.print("[");
    for (int i = 0; i < sp; i++) {
      System.out.printf("%X ", stack[i]);
    }
    System.out.println("]");
//    System.out.printf("] fp:%d sp:%d pc:%X inst:%X %n", fp, sp, pc, code[pc]);
  }

  void run(String filename, boolean trace) throws Exception {
    BufferedReader br = new BufferedReader(new FileReader(filename));
    int i = 0;
    for (String line = br.readLine(); line != null; line = br.readLine()) {
      code[i++] = Integer.parseInt(line, 16);
    }

    pc = 0;
    fp = 0;
    sp = 0;
    while (pc != -1) {
      int inst = code[pc];
      int data = inst <= 2 ? code[pc + 1] : 0;

      //System.out.println(inst);
      switch (inst) {
        case PIM: pim(data); break;
        case JNG: jng(data); break;
        case CLL: cll(data); break;
        case POP: pop(); pc++; break;
        case STO: sto(); break;
        case LDP: ldp(); break;
        case ADD: add(); break;
        case SUB: sub(); break;
        case MUL: mul(); break;
        case DIV: div(); break;
        case AND: and(); break;
        case OR:  or();  break;
        case NOT: not(); break;
        case RET: ret(); break;
        case PRN: prn(); break;
        case HLT: hlt();
      }
      if (trace) {
        printStack();
      }
    }
  }

  //-------------------------------------------------------------------
  // instructions
  //-------------------------------------------------------------------
  void pim(int n) {
    push(n);
    pc += 2;
  }

  void sto() {
    stack[fp + pop()] = pop();
    pc++;
  }

  void ldp() {
    push(stack[fp + pop()]);
    pc++;
  }

  void add() {
    push(pop() + pop());
    pc++;
  }

  void sub() {
    push(-pop() + pop());
    pc++;
  }

  void mul() {
    push(pop() * pop());
    pc++;
  }

  void div() {
    int n = pop();
    push(pop() / n);
    pc++;
  }

  void and() {
    push(pop() & pop());
    pc++;
  }

  void or() {
    push(pop() | pop());
    pc++;
  }

  void not() {
    push(pop() == 0 ? -1 : 0);
    pc++;
  }

  void jmp(int addr) {
    pc = addr;
  }

  void jng(int addr) {
    if (pop() < 0) {
      pc = addr;
    } else {
      pc += 2;
    }
  }

  void cll(int addr) {
    push(fp);
    push(pc + 2);
    fp = sp;
    pc = addr;
  }

  void ret() {
    sp = fp;
    pc = pop();
    fp = pop();
  }

  void prn() {
    System.out.println(pop());
    pc++;
  }

  void hlt() {
    pc = -1;
  }
}
Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s