public ushort CgSpecialReg(ParseTreeNode node, ref CgContext ctx, out Code? tail) { tail = null; switch (node.ChildNodes[0].Token.Text.ToLower()) { case "sp": return 0x1b; case "pc": return 0x1c; case "ex": return 0x1d; default: throw new UnexpectedGrammarException(); } }
public ushort CgRegLookup(ParseTreeNode node, ref CgContext ctx, out Code? tail) { tail = null; return (ushort)(8 + GeneralRegNumber(node.ChildNodes[0].ChildNodes[0].Token.Text)); }
public ushort EvalNumber(ParseTreeNode node, ref CgContext ctx) { var no = node.Token.Value; var nt = no.GetType(); if (nt == typeof(Int16)) return (ushort)(Int16)no; else return (UInt16)no; }
private static extern void cgGLRegisterStates(CgContext context);
public Code EvalLiteralWord(ParseTreeNode node, ref CgContext ctx) { var head = node.ChildNodes[0]; var tail = node.ChildNodes.Count > 1 ? node.ChildNodes[1] : null; var code = EvalLiteralWordAtom(head, ref ctx); if (tail != null) { var tailC = EvalLiteralWordAtom(tail, ref ctx); var diff = new Difference(code, tailC); code = ctx.EncodeDifference(diff); } return code; }
public ushort EvalCharacter(ParseTreeNode node, ref CgContext ctx) { return (ushort)(Char)node.Token.Value; }
public void CgExtInstruction(ParseTreeNode node, ref CgContext ctx) { var op = node.ChildNodes[0]; var arg = node.ChildNodes[1]; Instruction instr = new Instruction(); Code? tail; instr.BasicOpcode = BasicOpcode.Ext; instr.ExtOpcode = op.ChildNodes[0].Token.Text.ToExtOpcode(); instr.ArgA = CgArgument(arg, ref ctx, out tail, shortForm: false); ctx.Write(new Code(instr)); if (tail.HasValue) ctx.Write(tail.Value); }
public ushort CgLiteralWord(ParseTreeNode node, bool shortForm, ref CgContext ctx, out Code? tail) { tail = null; var valueCode = EvalLiteralWord(node, ref ctx); if (valueCode.Type == CodeType.Literal && !shortForm) { if (valueCode.Value <= 30 || valueCode.Value == 0xffff) return (ushort)(32 + (ushort)(valueCode.Value + 1)); } tail = valueCode; return 31; }
/* * The rest of the module generate specific grammar constructs. * The methods are named after the corresponding construct in the * grammar class. */ public void CgOptInstruction(ParseTreeNode node, ref CgContext ctx) { // OptInstruction is transient var childNode = node; switch (childNode.Term.Name) { case "BasicInstruction": CgBasicInstruction(childNode, ref ctx); return; case "ExtInstruction": CgExtInstruction(childNode, ref ctx); return; case "Data": CgData(childNode, ref ctx); return; default: throw new UnexpectedGrammarException(); } }
public void CgBasicInstruction(ParseTreeNode node, ref CgContext ctx) { var op = node.ChildNodes[0].ChildNodes[0]; var argB = node.ChildNodes[1]; var argA = node.ChildNodes[2]; Instruction instr = new Instruction(); Code? tailA, tailB; instr.BasicOpcode = op.Term.Name.ToBasicOpcode(); instr.ArgA = CgArgument(argA, ref ctx, out tailA, shortForm: false); instr.ArgB = CgArgument(argB, ref ctx, out tailB, shortForm: true); ctx.Write(new Code(instr)); if (tailA.HasValue) ctx.Write(tailA.Value); if (tailB.HasValue) ctx.Write(tailB.Value); }
/// <summary> /// The main entry point into the code generator, this assembles a /// complete, parsed source file. /// </summary> public CgResult CgProgram(ParseTreeNode node) { /* * If it weren't for labels, this would be a piece of cake. All * we'd have to do is produce cpu code for each instruction and * join them all together. * * But we *do* have to deal with labels, so there. We could handle * this by keeping track of a list of fixups; locations that contain * a forward reference. Then, once we know what that label resolves * to, we go back and do the fixups. * * However, I'd like to be able to do optimisation on the generated * code; specifically, replacing jumps to nearby labels with * relative jumps using add/sub pc, X. Doing this will cause the * address of all subsequent code (and labels) to change. * * In that case, it's probably simpler to just leave all labels * unresolved until *after* optimisation. But what happens when * we do shorten a given instruction? * * When we shorten a given instruction, all subsequent fixups need * to have their target address adjusted. * * An attractive alternative is to not keep a list of fixups; * instead, generated code is widened such that we can store * metadata for each word. This would include storing label * references directly. The advantage of this is that moving * code around is cheap. * * So that's what we'll do. * * For now, we'll just use a list to store the generated code. * Ideally, we'd have a linked list of pages since we won't be * doing a lot of cutting. */ var code = new List<Code>(); /* * This array stores difference literals. We need to do this * since difference literals can depend on labels but won't * fit in a code. */ var diffLits = new List<Difference>(); /* * We also need something to keep track of the defined labels. * Since we need to be able to pack this into code entries, * we'll stick them in a flat array. */ var labels = new List<Label>(); /* * A way of mapping a label name to a label object would also * be handy. */ var labelMap = new Dictionary<string, Label>(); /* * In order to implement local labels, we need to track the * last non-local label we saw. */ var lastGlobalLabel = InitialLabel; /* * We'll also need a function we can pass into the codegen * functions to turn a label name into a label object. */ LabelLookup lookup = delegate(string name) { if (name.StartsWith(".")) name = lastGlobalLabel + name; if (labelMap.ContainsKey(name)) return labelMap[name]; else { var index = (ushort)labels.Count; var label = new Label(index, name); labels.Add(label); labelMap[name] = label; return label; } }; /* * And while we're on the subject: a function to write to the * code list. */ CodeWriter write = delegate(Code c) { code.Add(c); }; Func<Difference, Code> diffToCode = delegate(Difference diff) { var index = (ushort)diffLits.Count; diffLits.Add(diff); return new Code(CodeType.Difference, index); }; /* * Whack 'em in a context. */ var ctx = new CgContext { Lookup = lookup, Write = write, GetCurrentAddress = () => (ushort)code.Count, EncodeDifference = diffToCode, }; /* * Ok, let's process those lines. */ foreach (var line in node.ChildNodes) { var labelNode = line.ChildNodes[0].ChildNodes.FirstOrDefault(); var instrNode = line.ChildNodes[1].ChildNodes.FirstOrDefault(); var labelName = labelNode != null ? labelNode.ChildNodes[0].Token.Text : null; if (labelName != null) { if (!labelName.StartsWith(".")) lastGlobalLabel = labelName; var label = lookup(labelName); if (label.Fixed) throw new CodegenException("Label '{0}' already defined at {1}.", labelName, label.Span.Location); if (instrNode != null && instrNode.Term.Name == "AddressFix") { var fix = EvalLiteralWord(instrNode.ChildNodes[0], ref ctx); switch (fix.Type) { case CodeType.Literal: label.Fix(fix.Value, labelNode.Span); break; case CodeType.Label: label.Fix(labels[fix.Value], labelNode.Span); break; case CodeType.Difference: throw new CodegenException("Labels cannot be fixed to difference literals"); default: throw new UnexpectedGrammarException(); } instrNode = null; } else { var addr = (ushort)code.Count; label.Fix(addr, labelNode.Span); } } if (instrNode != null) CgOptInstruction(instrNode, ref ctx); } /* * Let's add a few extra labels for fun. And usefulness. */ ctx.Lookup("__CODE_START").Fix(0, node.Span); ctx.Lookup("__CODE_END").Fix((ushort)code.Count, node.Span); /* * We now have code generated for the whole program. What we * we need to do now is go back and fill in the labels. * * Before that, let's just make sure that all labels were * actually defined somewhere... */ foreach (var label in labels) if (!label.Fixed) throw new CodegenException("Label '{0}' never defined.", label.Name); /* * Right. We now have enough information to generate the final, complete * binary. * * First of all, we'll fill in guesses for what the labels are attached to. */ foreach (var label in labels) { if (label.IsForwarded) continue; var addr = label.Value; if (addr >= code.Count) continue; switch (code[addr].Type) { case CodeType.Instruction: label.Type = LabelType.Code; break; case CodeType.Label: if( (code[addr].Flags & CodeFlags.IsLiteral) == 0 ) goto default; label.Type = LabelType.Data; break; case CodeType.Literal: label.Type = LabelType.Data; break; default: label.Type = LabelType.Unknown; break; } } /* * Now we can produce the output image. */ Func<Code, ushort> evalCode = null; evalCode = delegate(Code c) { switch (c.Type) { case CodeType.Label: return labels[c.Value].Value; case CodeType.Difference: { var diff = diffLits[c.Value]; return (ushort)(evalCode(diff.Target) - evalCode(diff.Base)); } default: return c.Value; } }; var image = new ushort[code.Count]; { var i = 0; foreach (var c in code) { image[i] = evalCode(c); ++i; } } /* * Done. Collect the results. */ labels.Sort((a, b) => a.Value - b.Value); return new CgResult { Image = image, Labels = labels, }; }
private static extern int cgGLGetManageTextureParameters(CgContext context);
private static extern void cgGLSetManageTextureParameters(CgContext context, bool flag);
public ushort CgRegOffLookup(ParseTreeNode node, ref CgContext ctx, out Code? tail) { var inner = node.ChildNodes[0]; var lhs = inner.ChildNodes[0]; var op = inner.ChildNodes[1]; var rhs = inner.ChildNodes[2]; ushort regNum = 0xffff; Code offsetCode; if (lhs.Term.Name == "GeneralRegister") { regNum = GeneralRegNumber(lhs.ChildNodes[0].Token.Text); offsetCode = EvalLiteralWord(rhs, ref ctx); // Note: op is actually wrapped in an unnamed production. if (op.ChildNodes[0].Token.Text == "-") offsetCode.Negate(); } else { regNum = GeneralRegNumber(rhs.ChildNodes[0].Token.Text); offsetCode = EvalLiteralWord(lhs, ref ctx); } tail = offsetCode; return (ushort)(16 + regNum); }
public void CgData(ParseTreeNode node, ref CgContext ctx) { var args = node.ChildNodes[1]; var i = 0; foreach (var arg in args.ChildNodes) { if (arg.Term.Name == "DataLength") ctx.Write(new Code(CountDataWords(args, i + 1, ref ctx))); else CgDataValue(arg, ref ctx); ++i; } }
public ushort CgStackOp(ParseTreeNode node, ref CgContext ctx, out Code? tail) { tail = null; //switch (node.ChildNodes[0].Token.Text.ToLower()) switch (node.ChildNodes[0].Term.Name) { case "StackPop": return 0x18; // assume in arg b case "StackPush": return 0x18; // assume in arg a case "StackPeek": return 0x19; case "StackPick": // Use length-1 since we could have either [sp,+,N] or [pick,N]. var pick = node.ChildNodes[0]; var off = pick.ChildNodes[pick.ChildNodes.Count - 1]; tail = EvalLiteralWordAtom(off, ref ctx); return 0x1a; default: throw new UnexpectedGrammarException(); } }
public ushort CountDataWords(ParseTreeNode datNode, int startAt, ref CgContext ctx) { var acc = (ushort)0; for (var i = startAt; i < datNode.ChildNodes.Count; ++i) { var val = datNode.ChildNodes[i]; switch (val.Term.Name) { case "string": acc += (ushort)EvalString(val, ref ctx).Length; break; default: acc++; break; } } return acc; }
public ushort CgLiteralLookup(ParseTreeNode node, ref CgContext ctx, out Code? tail) { tail = EvalLiteralWord(node.ChildNodes[0], ref ctx); return 30; }
public void CgDataValue(ParseTreeNode node, ref CgContext ctx) { // DataValue is transient // DataValue = [tilde |] string | number | character | identifier // Note that ~ is handled by the caller since, by this point, it's // too late to do anything. if (node.Term.Name == "string") { var s = EvalString(node, ref ctx); foreach (var ch in s) ctx.Write(new Code(ch)); } else { ctx.Write(EvalLiteralWord(node, ref ctx)); } }
public Code EvalLiteralWordAtom(ParseTreeNode node, ref CgContext ctx) { switch (node.Term.Name) { case "identifier": return new Code(EvalIdentifier(node, ref ctx)); case "character": return new Code(EvalCharacter(node, ref ctx)); case "number": return new Code(EvalNumber(node, ref ctx)); case "DifferenceLiteral": { var @base = ctx.GetCurrentAddress(); var target = EvalLiteralWordAtom(node.ChildNodes[0].ChildNodes[0], ref ctx); return ctx.EncodeDifference(new Difference(@base, target)); } case "DifferenceTo": return EvalLiteralWordAtom(node.ChildNodes[0], ref ctx); default: throw new UnexpectedGrammarException(); } }
public ushort CgArgument(ParseTreeNode node, ref CgContext ctx, out Code? tail, bool shortForm) { switch (node.Term.Name) { case "GeneralRegister": return CgGeneralReg(node, ref ctx, out tail); case "SpecialRegister": return CgSpecialReg(node, ref ctx, out tail); case "RegisterLookup": return CgRegLookup(node, ref ctx, out tail); case "RegisterOffsetLookup": return CgRegOffLookup(node, ref ctx, out tail); case "StackOp": return CgStackOp(node, ref ctx, out tail); case "LiteralWord": return CgLiteralWord(node, shortForm, ref ctx, out tail); case "LiteralLookup": return CgLiteralLookup(node, ref ctx, out tail); default: throw new UnexpectedGrammarException(); } }
public Label EvalIdentifier(ParseTreeNode node, ref CgContext ctx) { return ctx.Lookup((String)node.Token.Value); }
public ushort CgGeneralReg(ParseTreeNode node, ref CgContext ctx, out Code? tail) { tail = null; return GeneralRegNumber(node.ChildNodes[0].Token.Text); }
public string EvalString(ParseTreeNode node, ref CgContext ctx) { return (String)node.Token.Value; }
private static extern CgBuffer cgGLCreateBuffer(CgContext context, int size, IntPtr data, int bufferUsage);