Skip to content

OpeLa Language Specification

Kota UCHIDA edited this page Dec 28, 2020 · 41 revisions

OpeLa 言語仕様

OpeLa メインページ

プログラム例:割り込み

IDT の 21 に割り込みハンドラを登録し,割り込み許可(sti)する例です。

// 構造体の定義
// foo[n] は特別な構文で,接頭辞 foo が共通するメンバがグループ化される
type idtEntry struct {
  Offset[0]        address16;
  SegmentSelector  uint16;
  IST              uint3;
  _                uint5;
  Type             uint4;
  _                uint1;
  DPL              uint2;
  P                uint1;
  Offset[1]        address16;
  Offset[2]        address32;
  _                uint32;
};

// OpeLa の構造体にはパディング機能がないので明示的にパディングする
type stackFrame struct {
  SS    uint16;
  _     uint48;
  SP    address;
  Flags uint64;
  CS    uint16;
  _     uint48;
  IP    address;
};

// グローバル変数
var (
  idt idtEntry[256];
)

func notifyEndOfInterrupt() {
  // 組み込みの Atomic 型を使ってレジスタアクセス
  eoi *Atomic<uint32> := address(0xfee000b0);
  eoi->Store(0);
  // same as: *Atomic<uint32>(address(0xfee000b0))->Store(0)
}

// interrupt service routine
isr intHandler21(stackFrame *stackFrame) {
  Printk("INT21 CS:RIP = {:02x}:{:08x}\n", stackFrame->CS, stackFrame->IP);
  notifyEndOfInterrupt();
}

func main(argc int, argv *byte) {
  idt[21] = {
    .Offset = &intHandler21, .SegmentSelector = 1 * 8,
    .Type = 14, .DPL = 0, .P = 1
  };
  idtr packed_struct { _ uint16, _ address } := { sizeof(idt) - 1, &idt };
  intrin.Lidt(&idtr);
  intrin.Sti();

  for {
    intrin.Hlt();
  }
}

組み込み型

  • int/uint: int64/uint64 の別名
  • intN/uintN: N ビット幅の符号付き/符号無し整数
  • byte: uint8 の別名
  • address: ネイティブ幅のアドレス型(Intel 64 モードでは 64 ビット)
  • addressN: N ビット幅のアドレス型

OpeLa では char は組み込み型名ではない。

たとえ両辺が整数であっても、異なる型同士の計算はコンパイルエラー。

アドレス型

他の言語にない特徴的な型として address がある。アドレスはポインタから型情報を取り除いたものである。C の void* に近い。

任意のポインタと address は相互に暗黙的に変換可能。 address から整数へは暗黙的に変換可能。 整数から address へは明示的なキャスト address(整数) が必要。

定数リテラルの型は int

var v uint2 = 1; v = v + 3; では i は uint2、3 は int となる。型が異なるためコンパイルエラー。 正しくは var v uint2 = 1; v = v + uint2(3); とする。 ちなみに、v はオーバーフローして 0 となる。

ユーザー定義型

  • type Name T: T という型に Name と言う名前を付ける。Name は T とは異なる型となる。
  • struct {..}: 構造体型(パディングなし)

マスクフィールド

ページエントリのアドレスフィールドのように,下位 N ビットをマスクして読み書きすべきフィールドを定義できる。

type PageEntry struct {
  P    uint1
  RW   uint1
  US   uint1
  PWT  uint1
  PCD  uint1
  A    uint1
  D    uint1
  PAT  uint1
  G    uint1
  _    uint3
  Addr address64[63:12]
}

func f() {
  var e PageEntry
  e.Addr = 0x12345
  assert(e.Addr == 0x12000)
}

レジスタ差分定義

文字列

文字列は int8 の配列として扱う。

文字列は,将来的には Go と同じように読み取り専用のスライスとして実装したい。 現状では文字列を変数に格納するためには,先頭要素のポインタを取得する必要がある。

p := &"abc"[0];

配列

var x1 [3]int; --> int が 3 つ並んだ配列変数
x1[i]; --> 配列の i 番目の要素(i は 0 始まりの整数)
p := &x1[i]; --> 配列の i 番目の要素へのポインタ

配列へのポインタ

以下,仕様考え中…

p := &x1; --> p は x1 の先頭位置と要素数を持つ

言語仕様のヒントとなる情報群

Clone this wiki locally