rendered paste bodyusing System;
using System.IO;
using Nemerle.Collections;
using Nemerle.Compiler;
namespace Grace.Assembler.Macros {
public enum Opcode {
| Nop = 0x00
| Add = 0x01
| Sub = 0x02
| Mul = 0x03
| Div = 0x04
| Mod = 0x05
| Xor = 0x06
| Or = 0x07
| And = 0x08
| Not = 0x09
| Shl = 0x0A
| Shr = 0x0B
| AShr = 0x0C
| Neg = 0x0D
| Call = 0x20
| Return = 0x21
| Jmp = 0x30
| Jc = 0x31
| Jnc = 0x32
| Load = 0x40
| Store = 0x41
| Move = 0x42
| Push = 0x43
| Pop = 0x44
}
public variant Operand {
| Register {
Num : int
}
| BigReg {
Num : int
}
| Imm {
Num : int
}
| RelImm {
Num : int
}
}
public variant Instruction {
| Branch {
Type : Opcode;
Target : string;
}
| Final {
Opcode : Opcode;
OpA : Operand;
OpB : Operand;
OpC : Operand;
}
}
macro grace(file, body)
syntax("grace", "(", file, ")", body) {
def lines = match(body) {
| <[ { .. $lines } ]> =>
lines
| _ => null
}
mutable Instructions = [];
def Labels : Hashtable[string, int] = Hashtable();
mutable pos = 0;
def ParseOp(op) {
def op = op.ToString();
if(op.StartsWith("r")) {
Operand.Register(Convert.ToInt32(op.Substring(1)))
} else if(op.StartsWith("br")) {
Operand.BigReg(Convert.ToInt32(op.Substring(2)))
} else
Operand.Imm(Convert.ToInt32(op))
}
def ParseLine(line) {
| <[ $left = $right ]> =>
def left = ParseOp(left);
match(right) {
| <[ $a + $b ]> with op = Opcode.Add
| <[ $a - $b ]> with op = Opcode.Sub
| <[ $a * $b ]> with op = Opcode.Mul
| <[ $a / $b ]> with op = Opcode.Div
| <[ $a % $b ]> with op = Opcode.Mod
| <[ $a ^ $b ]> with op = Opcode.Xor
| <[ $a %| $b ]> with op = Opcode.Or
| <[ $a & $b ]> with op = Opcode.And
| <[ $a << $b ]> with op = Opcode.Shl
| <[ $a >> $b ]> with op = Opcode.Shr
| <[ $a >>> $b ]> with op = Opcode.AShr =>
Instructions = Instruction.Final(
op,
left,
ParseOp(a),
ParseOp(b)
) :: Instructions
| <[ ~ $a ]> with op = Opcode.Not
| <[ - $a ]> with op = Opcode.Neg =>
Instructions = Instruction.Final(
op,
left,
ParseOp(a),
null
) :: Instructions
| right =>
Instructions = Instruction.Final(
Opcode.Move,
left,
ParseOp(right),
null
) :: Instructions
}
pos += 8
| <[ label($label) ]> =>
Labels[label.ToString()] = pos
| <[ $j($label) ]> =>
Instructions = Instruction.Branch(
match(j) {
| <[ call ]> => Opcode.Call
| <[ jmp ]> => Opcode.Jmp
| _ => Opcode.Nop
},
label.ToString()
) :: Instructions;
pos += 8
| <[ return ]> =>
Instructions = Instruction.Final(
Opcode.Return,
null,
null,
null
) :: Instructions;
pos += 8
| _ => ()
}
def CountOps(a, b, c) {
match((a, b, c)) {
| (null, null, null) => 0
| (_, null, null) => 1
| (_, _, null) => 2
| (_, _, _) => 3
}
}
def EncodeForm(op : Operand) {
| null | Register => 0b00
| BigReg => 0b01
| Imm => 0b10
| RelImm => 0b11
}
def EncodeOp(op : Operand, buf, pos) {
match(op) {
| null with num = 0
| Register(num)
| BigReg(num)
| Imm(num)
| RelImm(num) =>
buf[pos] = ((num >> 8) & 0xFF) :> byte;
buf[pos+1] = (num & 0xFF) :> byte
}
}
foreach(line in lines) {
ParseLine(line)
}
pos = 0;
def code = array(Instructions.Length * 8);
foreach(inst in Instructions.Reverse()) {
def inst = (
match(inst) {
| Branch(btype, target) =>
Instruction.Final(
btype,
Operand.RelImm(Labels[target] - pos),
null,
null
)
| inst => inst
} :> Instruction.Final
);
def (opcd, a, b, c) = inst;
code[pos+0] = (
(CountOps(a, b, c) << 6) |
(EncodeForm(a) << 4) |
(EncodeForm(b) << 2) |
EncodeForm(c)
) :> byte;
code[pos+1] = opcd :> byte;
EncodeOp(a, code, pos+2);
EncodeOp(b, code, pos+4);
EncodeOp(c, code, pos+6);
pos += 8
}
File.OpenWrite(
match(file) {
| <[ $(file : string) ]> =>
file
| _ => null
}
).Write(code, 0, code.Length);
<[ () ]>
}
}