1 /* 2 Copyright (c) 2018 Clipsey 3 4 Permission is hereby granted, free of charge, to any person or organization 5 obtaining a copy of the software and accompanying documentation covered by 6 this license (the "Software") to use, reproduce, display, distribute, 7 execute, and transmit the Software, and to prepare derivative works of the 8 Software, and to permit third-parties to whom the Software is furnished to 9 do so, all subject to the following: 10 11 The copyright notices in the Software and this entire statement, including 12 the above license grant, this restriction and the following disclaimer, 13 must be included in all copies of the Software, in whole or in part, and 14 all derivative works of the Software, unless such copies or derivative 15 works are solely in the form of machine-executable object code generated by 16 a source language processor. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 21 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 22 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 23 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 DEALINGS IN THE SOFTWARE. 25 */ 26 module crisc; 27 import std.stdio; 28 import std..string; 29 import std.array; 30 import std.conv; 31 import std.file; 32 import std.algorithm; 33 34 public enum DBGOpCode : uint { 35 // PRINT a register 36 PRT_REG = 0, 37 38 // PRINT the program counter 39 PRT_CTR = 1, 40 41 // PRINT the program cycles 42 PRT_CYC = 2, 43 44 // PRINT the writable memory 45 PRT_WMEM = 3, 46 47 // PRINT the full memory. 48 PRT_FMEM = 4, 49 50 // PRINT memory range 51 PRT_MEMR = 5, 52 53 // PRINT the callstack. 54 PRT_CSTK = 6, 55 56 // PRINT the datastack. 57 PRT_DSTK = 7, 58 59 // SET verbose logging output 60 SET_VEB = 8, 61 62 // SET verbose logging for data stack operations. 63 SET_VSTK = 9, 64 } 65 66 public enum OpCode : ubyte { 67 // Kill program 68 HALT = 0, 69 70 // Move REG A to REG B 71 MOV = 1, 72 73 // Move CONST A to REG B 74 MOVC = 2, 75 76 // Move REG (Referenced by CONST) A to REG B 77 MOVR = 3, 78 79 ADD = 4, 80 81 // Add CONST A to REG B 82 ADDC = 5, 83 84 // Add REG (Referenced by CONST) A to REG B 85 ADDR = 6, 86 87 // Subtract REG A to REG B 88 SUB = 7, 89 90 // Subtract CONST A to REG B 91 SUBC = 8, 92 93 // Subtract REG (Referenced by CONST) A to REG B 94 SUBR = 9, 95 96 // Multiply REG A to REG B 97 MUL = 10, 98 99 // Multiply CONST A to REG B 100 MULC = 11, 101 102 // Multiply REG (Referenced by CONST) A to REG B 103 MULR = 12, 104 105 // Divide REG A to REG B 106 DIV = 13, 107 108 // Divide CONST A to REG B 109 DIVC = 14, 110 111 // Divide REG (Referenced by CONST) A to REG B 112 DIVR = 15, 113 114 // JUMP TO ADDRESS A 115 JMP = 16, 116 117 // JUMP TO CONST A 118 JMPC = 17, 119 120 // JUMP TO ADDRESS A IF STATUS register is NOT EQUAL to CONST 121 JMPNEQ = 18, 122 123 // JUMP TO ADDRESS A IF STATUS register is EQUAL to CONST 124 JMPEQ = 19, 125 126 // JUMP TO ADDRESS A IF STATUS register is EQUAL or LARGER than CONST B 127 JMPLEQ = 20, 128 129 // JUMP TO ADDRESS A IF STATUS register is EQUAL or SMALLER than CONST B 130 JMPSEQ = 21, 131 132 // JUMP TO CONST A IF STATUS register is NOT EQUAL to CONST 133 JMPNEQC = 22, 134 135 // JUMP TO CONST A IF STATUS register is EQUAL to CONST 136 JMPEQC = 23, 137 138 // JUMP TO CONST A IF STATUS register is EQUAL or LARGER than CONST B 139 JMPLEQC = 24, 140 141 // JUMP TO CONST A IF STATUS register is EQUAL or SMALLER than CONST B 142 JMPSEQC = 25, 143 144 // LOAD VALUE to REG A from (Referenced by CONST) MEMORY ADDRESS B 145 LDR = 26, 146 147 // LOAD VALUE TO REG A from (Referenced by CONST) MEMORY ADDRESS B 148 LDRC = 27, 149 150 // STORE VALUE from REG A to (Referenced by CONST) MEMORY ADDRESS B 151 STR = 28, 152 153 // STORE VALUE OF REG A to (Referenced by CONST) MEMORY ADDRESS B 154 STRC = 29, 155 156 // CALL jump to address referenced by CONST A and set stack return pointer 157 CALL = 30, 158 159 // CALL system level function. 160 SCALL = 31, 161 162 // PUSH value to stack 163 PUSH = 32, 164 165 // PUSH value to stack 166 PUSHC = 33, 167 168 // POP value from stack 169 POP = 34, 170 171 // RETURN returns to the last stack pointer with values 172 RET = 35, 173 174 // DBG debugging functionality 175 DBG = 36 176 } 177 178 struct Instruction { 179 OpCode opCode; 180 size_t[2] data; 181 } 182 183 struct CPUStack { 184 private { 185 size_t size; 186 ubyte* stackptr; 187 size_t stackoffset; 188 } 189 190 public { 191 void clearStack() { 192 stackoffset = 0; 193 while (stackoffset < size) { 194 stackpointer_t[stackoffset] = 0; 195 stackoffset++; 196 } 197 stackoffset = 0; 198 } 199 200 ubyte* stackpointer() { 201 return stackptr+stackoffset; 202 } 203 204 size_t* stackpointer_t() { 205 return (cast(size_t*)stackptr)+stackoffset; 206 } 207 208 void push(size_t item) { 209 checkBounds(1); 210 *((cast(size_t*)stackpointer_t)) = item; 211 stackoffset += 1; 212 } 213 214 size_t pop() { 215 checkBounds(-1); 216 stackoffset -= 1; 217 size_t item = *((cast(size_t*)stackpointer_t)); 218 return item; 219 } 220 221 void checkBounds(long offset) { 222 if (offset < 0) { 223 if (stackoffset == 0 || cast(long)(stackoffset)-offset < 0) throw new Exception("Stack underflow"); 224 } else { 225 if (stackoffset+offset > size) 226 throw new Exception("Stack overflow!\nStack:\n"~stackStr); 227 } 228 } 229 230 string stackStr() { 231 return to!string((stackpointer_t-stackoffset)[0..size]) ~ "; OFFSET=" ~ to!string(stackoffset); 232 } 233 } 234 } 235 236 class SysCall { 237 public string name; 238 239 this(string name) { 240 this.name = name; 241 } 242 243 this(string name, CPU owner) { 244 this.name = name; 245 this.valueptr = &owner.datastack; 246 } 247 248 this(string name, CPUStack* stack) { 249 this.name = name; 250 this.valueptr = stack; 251 } 252 253 protected CPUStack* valueptr; 254 public abstract void execute(); 255 } 256 257 class SysCallGetSafeMem : SysCall { 258 CPU cpu; 259 260 this() { 261 super("gsfm"); 262 } 263 264 this(CPU cpu) { 265 super("gsfm", cpu); 266 this.cpu = cpu; 267 } 268 269 public override void execute() { 270 valueptr.push(cast(size_t)cpu.safeMemOffset); 271 } 272 } 273 274 class CPU { 275 // Program counter/program pointer. 276 Instruction* progptr; 277 278 // Pointer to start of program 279 Instruction* progstart; 280 281 size_t progctr() { 282 return progptr-progstart; 283 } 284 285 // List of system calls (NOTE NEEDS TO BE IN SAME ORDER AS ASSEMBLED) 286 SysCall[] syscalls; 287 288 // Registers 289 ulong[256] REGISTERS; 290 291 // Pointer to status register (0xFF) 292 ulong* STATUS_REG; 293 294 // Call stack 295 CPUStack callstack; 296 297 // Data stack 298 CPUStack datastack; 299 300 // The memory in which the program resides. 301 ubyte[] memory; 302 303 // safe memory space offset 304 size_t safeMemOffset; 305 306 // Amount of operations/instructions program has run 307 ulong cOps = 0; 308 309 // Sizes for stacks 310 ulong callstackSize; 311 ulong stackStoreSize; 312 313 // Verbose and Stack Verbose 314 bool VEB = false; 315 bool SVEB = false; 316 317 bool running() { 318 return (progptr !is null); 319 } 320 321 322 this(ubyte[] program, size_t stackSize, size_t memorySize) { 323 // Set up status register pointer. 324 STATUS_REG = ®ISTERS[255]; 325 326 // Prepare memory. 327 memory = program; 328 memory.length += stackSize; 329 memory.length += memorySize; 330 331 // Set stack pointer. 332 CPUStack cstack = { size:stackSize, stackptr:memory.ptr+program.length, stackoffset:0 }; 333 callstack = cstack; 334 335 // Set stack pointer for data. 336 CPUStack dstack = { size:stackSize, stackptr:(memory.ptr+program.length)+(size_t.sizeof*stackSize), stackoffset:0 }; 337 datastack = dstack; 338 339 // Set program counter and program start pointer 340 progstart = cast(Instruction*)memory.ptr; 341 progptr = progstart; 342 343 // Clear stacks 344 callstack.clearStack(); 345 datastack.clearStack(); 346 347 safeMemOffset = (program.length)+((size_t.sizeof*stackSize)*2); 348 349 // Add ptrc and rdc syscalls. 350 this.syscalls = cast(SysCall[])[new SysCallGetSafeMem(this)]; 351 } 352 353 public void PushSyscalls(SysCall[] syscalls) { 354 this.syscalls ~= syscalls; 355 } 356 357 void runCycle() { 358 if (progptr is null) return; 359 REGISTERS[254] = cast(size_t)callstack.stackpointer; 360 debugInstr(*progptr); 361 switch (progptr.opCode) { 362 363 case(OpCode.MOV): REGISTERS[progptr.data[1]] = REGISTERS[progptr.data[0]]; break; 364 case(OpCode.MOVC): REGISTERS[progptr.data[1]] = progptr.data[0]; break; 365 case(OpCode.MOVR): REGISTERS[REGISTERS[progptr.data[1]]] = progptr.data[0]; break; 366 367 case(OpCode.ADD): REGISTERS[progptr.data[1]] += REGISTERS[progptr.data[0]]; break; 368 case(OpCode.ADDC): REGISTERS[progptr.data[1]] += progptr.data[0]; break; 369 case(OpCode.ADDR): REGISTERS[REGISTERS[progptr.data[1]]] += progptr.data[0]; break; 370 371 case(OpCode.SUB): REGISTERS[progptr.data[1]] -= REGISTERS[progptr.data[0]]; break; 372 case(OpCode.SUBC): REGISTERS[progptr.data[1]] -= progptr.data[0]; break; 373 case(OpCode.SUBR): REGISTERS[REGISTERS[progptr.data[1]]] -= progptr.data[0]; break; 374 375 case(OpCode.MUL): REGISTERS[progptr.data[1]] *= REGISTERS[progptr.data[0]]; break; 376 case(OpCode.MULC): REGISTERS[progptr.data[1]] *= progptr.data[0]; break; 377 case(OpCode.MULR): REGISTERS[REGISTERS[progptr.data[1]]] *= progptr.data[0]; break; 378 379 case(OpCode.DIV): REGISTERS[progptr.data[1]] /= REGISTERS[progptr.data[0]]; break; 380 case(OpCode.DIVC): REGISTERS[progptr.data[1]] /= progptr.data[0]; break; 381 case(OpCode.DIVR): REGISTERS[REGISTERS[progptr.data[1]]] /= progptr.data[0]; break; 382 383 case(OpCode.JMP): progptr = progstart+(REGISTERS[progptr.data[0]])-1; break; 384 385 case(OpCode.JMPEQ): 386 if (*STATUS_REG == REGISTERS[progptr.data[1]]) progptr = progstart+(progptr.data[0])-1; 387 break; 388 389 case(OpCode.JMPNEQ): 390 if (*STATUS_REG != REGISTERS[progptr.data[1]]) progptr = progstart+(progptr.data[0])-1; 391 break; 392 393 case(OpCode.JMPLEQ): 394 if (*STATUS_REG >= REGISTERS[progptr.data[1]]) progptr = progstart+(progptr.data[0])-1; 395 break; 396 397 case(OpCode.JMPSEQ): 398 if (*STATUS_REG <= REGISTERS[progptr.data[1]]) progptr = progstart+(progptr.data[0])-1; 399 break; 400 401 case(OpCode.JMPC): progptr = progstart+(progptr.data[0])-1; break; 402 403 case(OpCode.JMPEQC): 404 if (*STATUS_REG == progptr.data[1]) progptr = progstart+(progptr.data[0])-1; 405 break; 406 407 case(OpCode.JMPNEQC): 408 if (*STATUS_REG != progptr.data[1]) progptr = progstart+(progptr.data[0])-1; 409 break; 410 411 case(OpCode.JMPLEQC): 412 if (*STATUS_REG >= progptr.data[1]) progptr = progstart+(progptr.data[0])-1; 413 break; 414 415 case(OpCode.JMPSEQC): 416 if (*STATUS_REG <= progptr.data[1]) progptr = progstart+(progptr.data[0])-1; 417 break; 418 419 case(OpCode.DBG): 420 if (progptr.data[0] == DBGOpCode.PRT_REG) writeln("REG_", progptr.data[1], "=", REGISTERS[progptr.data[1]]); 421 if (progptr.data[0] == DBGOpCode.PRT_CTR) writeln("PROG_CTR=", progptr); 422 if (progptr.data[0] == DBGOpCode.PRT_CYC) writeln("CYCLES=", cOps); 423 if (progptr.data[0] == DBGOpCode.PRT_WMEM) writeln("MEMORY MAP=", to!string(memory)); 424 if (progptr.data[0] == DBGOpCode.PRT_DSTK) writeln("DATASTACK=", datastack.stackStr); 425 if (progptr.data[0] == DBGOpCode.PRT_CSTK) writeln("CALLSTACK=", callstack.stackStr); 426 if (progptr.data[0] == DBGOpCode.PRT_MEMR) writeln(to!string(readMemRange(REGISTERS[253], progptr.data[1]))); 427 428 429 if (progptr.data[0] == DBGOpCode.SET_VEB) VEB = cast(bool)progptr.data[1]; 430 if (progptr.data[0] == DBGOpCode.SET_VSTK) SVEB = cast(bool)progptr.data[1]; 431 break; 432 433 case(OpCode.CALL): 434 if (progptr.data[0] < 0) throw new Exception("CPU HALT; ACCESS OUT OF BOUNDS"); 435 callstack.push(progctr+1); 436 if (SVEB) writeln("DATASTACK=", datastack.stackStr); 437 progptr = progstart+(progptr.data[0])-1; 438 break; 439 440 case(OpCode.SCALL): syscalls[progptr.data[0]].execute(); break; 441 442 case(OpCode.RET): 443 size_t tptr = callstack.pop(); 444 progptr = progstart+tptr-1; 445 if (SVEB) writeln("DATASTACK=", datastack.stackStr); 446 break; 447 448 case(OpCode.PUSHC): 449 datastack.push(progptr.data[0]); 450 if (SVEB) writeln("DATASTACK=", datastack.stackStr); 451 break; 452 453 case(OpCode.PUSH): 454 datastack.push(REGISTERS[progptr.data[0]]); 455 if (SVEB) writeln("DATASTACK=", datastack.stackStr); 456 break; 457 458 case(OpCode.POP): 459 REGISTERS[progptr.data[0]] = datastack.pop(); 460 if (SVEB) writeln("DATASTACK=", datastack.stackStr); 461 break; 462 463 case(OpCode.LDR): REGISTERS[progptr.data[1]] = readMem(REGISTERS[progptr.data[0]]); break; 464 case(OpCode.LDRC): REGISTERS[progptr.data[1]] = readMem(progptr.data[0]); break; 465 466 case(OpCode.STR): writeMem(REGISTERS[progptr.data[1]], REGISTERS[progptr.data[0]]); break; 467 case(OpCode.STRC): writeMem(REGISTERS[progptr.data[1]], progptr.data[0]); break; 468 469 case(OpCode.HALT): 470 writeln("PROGRAM HALTED."); 471 progptr = null; 472 break; 473 474 default: 475 writeln("INVALID OPERATION @", progptr-progstart); 476 break; 477 } 478 if (progptr is null) return; 479 progptr++; 480 cOps++; 481 } 482 483 private size_t readMem(size_t address) { 484 size_t value = *cast(size_t*)(cast(ubyte*)memory+address); 485 //writeln("Reading ", value, " fom ", address); 486 return value; 487 } 488 489 private size_t[] readMemRange(size_t address, size_t length) { 490 //writeln("Reading address ", address, " to ", address+length); 491 return (cast(size_t*)((cast(ubyte*)memory+address)[0..length]))[0..length/size_t.sizeof]; 492 } 493 494 private void writeMem(size_t address, size_t value) { 495 //writeln("Writing ", value, " to ", address); 496 *cast(size_t*)(cast(ubyte*)memory+address) = value; 497 } 498 499 private void debugInstr(Instruction instr) { 500 if (VEB) writeln(to!string((cast(OpCode)instr.opCode)), " ", instr.data[0], " ", instr.data[1]); 501 } 502 } 503 504 struct Label { 505 string name; 506 size_t offset; 507 } 508 509 struct LabelRef { 510 string name; 511 size_t doffset; 512 size_t offset; 513 } 514 515 class Compiler { 516 private LabelRef[] labelRefs; 517 private Instruction[] code; 518 private Label[] labels; 519 private bool doInfer; 520 521 private SysCall[] syscalls; 522 523 public this(bool infer, SysCall[] syscalls) { 524 this.doInfer = infer; 525 526 // Add ptrc and rdc syscalls. 527 this.syscalls = cast(SysCall[])[new SysCallGetSafeMem()] ~ syscalls; 528 } 529 530 public ubyte[] compile(string asmCode) { 531 // Process lines in program, removing/ignoring comments. 532 string[] lines = asmCode.split('\n'); 533 string[] keywords; 534 string[string] definitions; 535 536 bool skip = false; 537 foreach(string line; lines) { 538 string lo = ""; 539 bool isComment = false; 540 bool isPreprocessorDirective = false; 541 foreach (int i, char c; line) { 542 if (c == ';') isComment = true; 543 if (i == 0 && c == '#') isPreprocessorDirective = true; 544 if (!isComment && !isPreprocessorDirective && !skip) lo ~= c; 545 } 546 if (isPreprocessorDirective) { 547 string[] directive = line[1..$].split(' '); 548 if (directive.length > 0) { 549 if (directive[0] == "define") { 550 definitions[directive[1]] = ""; 551 if (directive.length == 3) { 552 definitions[directive[1]] = directive[2]; 553 } 554 } 555 556 if (directive[0] == "ifdef") { 557 skip = true; 558 if (directive[1] in definitions) { 559 skip = false; 560 } 561 } 562 563 if (directive[0] == "ifndef") { 564 skip = true; 565 if (directive[1] !in definitions) { 566 skip = false; 567 } 568 } 569 570 if (directive[0] == "undef") { 571 if (directive[1] in definitions) definitions.remove(directive[1]); 572 } 573 574 if (directive[0] == "endif") { 575 skip = false; 576 } 577 } else { 578 throw new Exception("Invalid preprocessor directive \""~directive[0]~"\"! Directive must contain 1 or more tags/datapairs."); 579 } 580 } 581 582 foreach (string keyword; lo.split) { 583 if (keyword in definitions) keywords ~= definitions[keyword]; 584 else if (keyword != "") keywords ~= keyword; 585 } 586 } 587 588 589 // Convert text/asm to instructions. 590 bool parsingCompleted = false; 591 int i = 0; 592 uint instr_pos = 0; 593 while (!parsingCompleted) { 594 try { 595 // Generate labels. 596 if (i >= keywords.length) break; 597 if (keywords[i].endsWith(":")) { 598 Label l = { keywords[i][0..$-1], instr_pos }; 599 labels ~= l; 600 } else { 601 // Preprocessing 602 OpCode opCode = getOp(keywords[i]); 603 string kw = keywords[i]; 604 605 // Specifies whether the assembler should infer which instruction to use based on how the arguments are structured. 606 if (doInfer) { 607 if (opCode != OpCode.HALT && opCode != OpCode.RET && opCode != OpCode.DBG && opCode != OpCode.CALL && opCode != OpCode.SCALL) { 608 int r = 1; 609 if (kw.toUpper.startsWith("JMP")) { 610 r = 2; 611 } 612 if (!keywords[i+r].startsWith("@")) { 613 if (opCode == OpCode.POP) throw new Exception("Invalid operation, \""~kw~"\" [arg a] takes an register, not a constant!"); 614 // Handle references. 615 kw ~= "C"; 616 } 617 if (!kw.toUpper.startsWith("JMP")) { 618 if (opCode != OpCode.POP && opCode != OpCode.JMP && opCode != OpCode.PUSH) { 619 if (!keywords[i+2].startsWith("@")) throw new Exception("Invalid operation, \""~kw~"\" [arg b] takes an register, not a constant!"); 620 } 621 } 622 } 623 } 624 625 // Generate instructions. 626 opCode = getOp(kw); 627 628 string argAStr = ""; 629 if (i+1 < keywords.length) argAStr = keywords[i+1]; 630 uint argA = 0; 631 632 string argBStr = ""; 633 if (i+2 < keywords.length) argBStr = keywords[i+2]; 634 uint argB = 0; 635 if (opCode != OpCode.HALT && opCode != OpCode.RET) { 636 argAStr = getValMacro(definitions, argAStr); 637 if (opCode == OpCode.DBG) { 638 argA = getDBGOp(argAStr); 639 } else if (opCode == OpCode.SCALL) { 640 argA = getSyscall(argAStr); 641 } else { 642 argA = getVal(labels, 0, argAStr); 643 } 644 645 // Iterate 646 i++; 647 argBStr = getValMacro(definitions, argBStr); 648 649 if (opCode != OpCode.CALL && opCode != OpCode.SCALL && opCode != OpCode.PUSH && opCode != OpCode.PUSHC && opCode != OpCode.POP && opCode != OpCode.JMP && opCode != OpCode.JMPC) { 650 argB = getVal(labels, 1, argBStr); 651 652 // Iterate 653 i++; 654 } 655 656 } 657 Instruction instr = { opCode, [argA, argB] }; 658 code ~= instr; 659 instr_pos++; 660 } 661 // Iterate 662 i++; 663 if (i >= keywords.length) parsingCompleted = true; 664 } catch (Exception ex) { 665 writeln("Error @ index ", i, ", token=", keywords[i], " message=", ex.message); 666 return null; 667 } 668 } 669 670 // Post processing (label conversion) 671 foreach(Label l; labels) { 672 size_t x = 0; 673 while (true) { 674 if (x >= labelRefs.length) break; 675 LabelRef lref = labelRefs[x]; 676 Instruction* instr = &code[lref.offset]; 677 if (lref.name == l.name) { 678 instr.data[lref.doffset] = cast(uint)l.offset; 679 labelRefs = labelRefs.remove(x); 680 continue; 681 682 //throw new Exception("Invalid reference to label for OPCode "~to!string(cast(OpCode)(instr.opCode))); 683 } 684 x++; 685 } 686 } 687 688 return cast(ubyte[])code; 689 } 690 691 string getValMacro(string[string] macros, string name, bool throwExceptionOnFailure = false) { 692 if (name in macros) { 693 return macros[name]; 694 } 695 if (throwExceptionOnFailure) throw new Exception("Macro defintion not found in macro definitions!"); 696 return name; 697 } 698 699 uint getValLabels(Label[] labels, string label) { 700 foreach(Label l; labels) { 701 if (l.name == label) return cast(uint)l.offset; 702 } 703 return -1; 704 } 705 706 // # - Label 707 // @ - Reference/Register 708 // TODO: * - Address 709 710 uint getSyscall(string t) { 711 if (t.startsWith("#")) { 712 foreach(i; 0 .. syscalls.length) { 713 if (syscalls[i].name.toLower == t[1..$].toLower) 714 return cast(uint)i; 715 } 716 throw new Exception("syscall "~t~" not found!"); 717 } 718 if (t.startsWith("@")) { 719 return to!uint(t[1..$]); 720 } 721 return to!uint(t); 722 } 723 724 uint getVal(Label[] labels, size_t owner_offset, string t) { 725 if (t.startsWith("#")) { 726 LabelRef r = {t[1..$], owner_offset, code.length}; 727 labelRefs ~= r; 728 return 0; 729 } 730 if (t.startsWith("@")) { 731 t = t[1..$]; 732 } 733 if (t.startsWith("0x")) { 734 return to!uint(t[2..$], 16); 735 } 736 return to!uint(t); 737 } 738 739 OpCode getOp(string name) { 740 return to!OpCode(name.toUpper); 741 } 742 743 DBGOpCode getDBGOp(string name) { 744 return to!DBGOpCode(name.toUpper); 745 } 746 747 void printLabels() { 748 writeln("Labels:"); 749 foreach(Label l; labels) { 750 writeln("\t", l.name, "@", l.offset); 751 } 752 } 753 } 754 755 public string binToASMDESC(ubyte[] data) { 756 Instruction[] instructions = (cast(Instruction*)data)[0..data.length/Instruction.sizeof]; 757 string oi = ""; 758 int line = 0; 759 foreach(Instruction i; instructions) { 760 oi ~= "\t" ~ to!string(line) ~ "\t" ~ to!string(i.opCode) ~ " " ~ to!string(i.data[0]) ~ " " ~ to!string(i.data[1]) ~ "\n"; 761 line++; 762 } 763 return oi; 764 }