1 /** 2 * Intel 8080 assembler. 3 */ 4 module a80.i80; 5 import std.stdio; 6 import std.algorithm; 7 import std.string; 8 import std.ascii; 9 import std.conv; 10 import std.exception; 11 12 /** 13 * Line number. 14 */ 15 static size_t line; 16 17 /** 18 * Pass. 19 */ 20 static int pass; 21 22 /** 23 * Output stored in memory until we're finished. 24 */ 25 static ubyte[] output; 26 27 /** 28 * Address for labels. 29 */ 30 static ushort addr; 31 32 /** 33 * Symbol table. 34 */ 35 struct symtab 36 { 37 string name; /// Symbol name 38 ushort value; /// Symbol address 39 }; 40 41 /** 42 * Symbol table is an array of entries. 43 */ 44 static symtab[] stab; 45 46 /** 47 * 8 and 16 bit immediates 48 */ 49 enum IMM8 = 8; 50 enum IMM16 = 16; 51 52 /** 53 * Intel 8080 assembler instruction. 54 */ 55 class i80 56 { 57 string lab; /// Label 58 string op; /// Instruction mnemonic 59 string a1; /// First argument 60 string a2; /// Second argument 61 string comm; /// Comment 62 63 /** 64 * Parse each line into (up to) five tokens. 65 */ 66 void parse(string line) { 67 auto dbFix = 0; 68 auto preprocess = stripLeft(line); 69 70 auto splitcomm = preprocess.findSplit(";"); 71 if (!splitcomm[2].empty) 72 comm = strip(splitcomm[2]); 73 74 auto splita2 = splitcomm[0].findSplit(","); 75 if (!splita2[2].empty) 76 a2 = strip(splita2[2]); 77 78 auto splita1 = splita2[0].findSplit("\t"); 79 if (!splita1[2].empty) { 80 a1 = strip(splita1[2]); 81 } else { 82 splita1 = splita2[0].findSplit(" "); 83 if (!splita1[2].empty) { 84 a1 = strip(splita1[2]); 85 } 86 } 87 88 /** 89 * Fixup for the db 'string$' case. 90 */ 91 if ((!a1.empty && (a1[0] == '\'' || a1[a1.length - 1] == '\'')) || 92 (!a2.empty && (a2[0] == '\'' || a2[a2.length - 1] == '\''))) { 93 splita1 = splitcomm[0].findSplit("'"); 94 a1 = strip(chompPrefix(chop(strip(splita1[2])), "'")); 95 a2 = null; 96 dbFix = 1; 97 } 98 99 auto splitop = splita1[0].findSplit(":"); 100 if (!splitop[1].empty) { 101 op = strip(splitop[2]); 102 lab = strip(splitop[0]); 103 } else { 104 op = strip(splitop[0]); 105 } 106 107 /** 108 * Fixup for the label: op case. 109 */ 110 if (dbFix == 0) { 111 auto opFix = a1.findSplit("\t"); 112 if (!opFix[1].empty) { 113 op = strip(opFix[0]); 114 a1 = strip(opFix[2]); 115 } else { 116 opFix = a1.findSplit(" "); 117 if (!opFix[1].empty) { 118 op = strip(opFix[0]); 119 a1 = strip(opFix[2]); 120 } 121 } 122 } 123 } 124 } 125 126 /** 127 * Top-level assembly function. 128 * Everything cascades downward from here. 129 * Repeat the parsing twice. 130 * Pass 1 gathers symbols and their addresses/values. 131 * Pass 2 emits code. 132 */ 133 void assemble(string[] s, string name) 134 { 135 /* Pass 1 */ 136 pass = 1; 137 for (line = 0; line < s.length; line++) { 138 i80 insn = new i80; 139 140 insn.parse(s[line]); 141 process(insn); 142 } 143 144 /* Pass 2 */ 145 pass = 2; 146 for (line = 0; line < s.length; line++) { 147 i80 insn = new i80; 148 149 insn.parse(s[line]); 150 process(insn); 151 } 152 153 fileWrite(name); 154 } 155 156 /** 157 * After all code is emitted, write it out to a file. 158 */ 159 static void fileWrite(string name) { 160 import std.file : write; 161 162 write(name, output); 163 } 164 165 /** 166 * Figure out which op we have. 167 */ 168 static void process(i80 insn) 169 { 170 auto op = insn.op; 171 172 /** 173 * Special case for if you put a label by itself on a line. 174 * Or have a totally blank line. 175 */ 176 if (insn.op.empty && insn.a1.empty && insn.a2.empty) { 177 passAct(0, -1, insn); 178 return; 179 } 180 181 /** 182 * Remember: we're trying to demystify. 183 * You (the reader) can do better. 184 * Perhaps try a hash table? 185 */ 186 if (op == "nop") 187 nop(insn); 188 else if (op == "lxi") 189 lxi(insn); 190 else if (op == "stax") 191 stax(insn); 192 else if (op == "inx") 193 inx(insn); 194 else if (op == "inr") 195 inr(insn); 196 else if (op == "dcr") 197 dcr(insn); 198 else if (op == "mvi") 199 mvi(insn); 200 else if (op == "rlc") 201 rlc(insn); 202 else if (op == "dad") 203 dad(insn); 204 else if (op == "ldax") 205 ldax(insn); 206 else if (op == "dcx") 207 dcx(insn); 208 else if (op == "rrc") 209 rrc(insn); 210 else if (op == "ral") 211 ral(insn); 212 else if (op == "rar") 213 rar(insn); 214 else if (op == "shld") 215 shld(insn); 216 else if (op == "daa") 217 daa(insn); 218 else if (op == "lhld") 219 lhld(insn); 220 else if (op == "cma") 221 cma(insn); 222 else if (op == "sta") 223 sta(insn); 224 else if (op == "stc") 225 stc(insn); 226 else if (op == "lda") 227 lda(insn); 228 else if (op == "cmc") 229 cmc(insn); 230 else if (op == "mov") 231 mov(insn); 232 else if (op == "hlt") 233 hlt(insn); 234 else if (op == "add") 235 add(insn); 236 else if (op == "adc") 237 adc(insn); 238 else if (op == "sub") 239 sub(insn); 240 else if (op == "sbb") 241 sbb(insn); 242 else if (op == "ana") 243 ana(insn); 244 else if (op == "xra") 245 xra(insn); 246 else if (op == "ora") 247 ora(insn); 248 else if (op == "cmp") 249 cmp(insn); 250 else if (op == "rnz") 251 rnz(insn); 252 else if (op == "pop") 253 pop(insn); 254 else if (op == "jnz") 255 jnz(insn); 256 else if (op == "jmp") 257 jmp(insn); 258 else if (op == "cnz") 259 cnz(insn); 260 else if (op == "push") 261 push(insn); 262 else if (op == "adi") 263 adi(insn); 264 else if (op == "rst") 265 rst(insn); 266 else if (op == "rz") 267 rz(insn); 268 else if (op == "jz") 269 jz(insn); 270 else if (op == "cz") 271 cz(insn); 272 else if (op == "call") 273 call(insn); 274 else if (op == "aci") 275 aci(insn); 276 else if (op == "rnc") 277 rnc(insn); 278 else if (op == "jnc") 279 jnc(insn); 280 else if (op == "out") 281 i80_out(insn); 282 else if (op == "cnc") 283 cnc(insn); 284 else if (op == "sui") 285 sui(insn); 286 else if (op == "rc") 287 rc(insn); 288 else if (op == "jc") 289 jc(insn); 290 else if (op == "in") 291 i80_in(insn); 292 else if (op == "cc") 293 cc(insn); 294 else if (op == "sbi") 295 sbi(insn); 296 else if (op == "rpo") 297 rpo(insn); 298 else if (op == "jpo") 299 jpo(insn); 300 else if (op == "xthl") 301 xthl(insn); 302 else if (op == "cpo") 303 cpo(insn); 304 else if (op == "ani") 305 ani(insn); 306 else if (op == "rpe") 307 rpe(insn); 308 else if (op == "pchl") 309 pchl(insn); 310 else if (op == "jpe") 311 jpe(insn); 312 else if (op == "xchg") 313 xchg(insn); 314 else if (op == "cpe") 315 cpe(insn); 316 else if (op == "xri") 317 xri(insn); 318 else if (op == "rp") 319 rp(insn); 320 else if (op == "jp") 321 jp(insn); 322 else if (op == "di") 323 di(insn); 324 else if (op == "cp") 325 cp(insn); 326 else if (op == "ori") 327 ori(insn); 328 else if (op == "rm") 329 rm(insn); 330 else if (op == "sphl") 331 sphl(insn); 332 else if (op == "jm") 333 jm(insn); 334 else if (op == "ei") 335 ei(insn); 336 else if (op == "cm") 337 cm(insn); 338 else if (op == "cpi") 339 cpi(insn); 340 else if (op == "equ") 341 equ(insn); 342 else if (op == "db") 343 db(insn); 344 else if (op == "org") 345 org(insn); 346 else 347 err("unknown opcode: " ~ op); 348 } 349 350 /** 351 * Take action depending on which pass this is. 352 */ 353 static void passAct(ushort a, int b, i80 insn) 354 { 355 if (pass == 1) { 356 if (!insn.lab.empty) 357 addsym(insn.lab, addr); 358 addr += a; 359 } else { 360 if (b != -1) 361 output ~= cast(ubyte)b; 362 } 363 } 364 365 /** 366 * Add a symbol to the symbol table. 367 */ 368 static void addsym(string lab, ushort a) 369 { 370 for (size_t i = 0; i < stab.length; i++) { 371 if (lab == stab[i].name) 372 err("duplicate label: " ~ lab); 373 } 374 375 symtab nsym = { lab, a }; 376 stab ~= nsym; 377 } 378 379 /** 380 * nop (0x00) 381 */ 382 static void nop(i80 insn) 383 { 384 argcheck(insn.a1.empty && insn.a2.empty); 385 passAct(1, 0x00, insn); 386 } 387 388 /** 389 * lxi (0x01 + 16 bit register offset) 390 */ 391 static void lxi(i80 insn) 392 { 393 argcheck(!insn.a1.empty && !insn.a2.empty); 394 passAct(3, 0x01 + regMod16(insn), insn); 395 imm(insn, IMM16); 396 } 397 398 /** 399 * stax (0x02 + 16 bit register offset) 400 */ 401 static void stax(i80 insn) 402 { 403 argcheck(!insn.a1.empty && insn.a2.empty); 404 if (insn.a1 == "b") 405 passAct(1, 0x02, insn); 406 else if (insn.a1 == "d") 407 passAct(1, 0x12, insn); 408 else 409 err("stax only takes b or d"); 410 } 411 412 /** 413 * inx (0x03 + 16 bit register offset) 414 */ 415 static void inx(i80 insn) 416 { 417 argcheck(!insn.a1.empty && insn.a2.empty); 418 passAct(1, 0x03 + regMod16(insn), insn); 419 } 420 421 /** 422 * inr (0x04 + 8 bit register offset) 423 */ 424 static void inr(i80 insn) 425 { 426 argcheck(!insn.a1.empty && insn.a2.empty); 427 passAct(1, 0x04 + regMod8(insn.a1), insn); 428 } 429 430 /** 431 * dcr (0x05 + 8 bit register offset) 432 */ 433 static void dcr(i80 insn) 434 { 435 argcheck(!insn.a1.empty && insn.a2.empty); 436 passAct(1, 0x05 + regMod8(insn.a1), insn); 437 } 438 439 /** 440 * mvi (0x06 + (8 bit register offset << 3)) 441 */ 442 static void mvi(i80 insn) 443 { 444 argcheck(!insn.a1.empty && !insn.a2.empty); 445 passAct(2, 0x06 + (regMod8(insn.a1) << 3), insn); 446 imm(insn, IMM8); 447 } 448 449 /** 450 * rcl (0x07) 451 */ 452 static void rlc(i80 insn) 453 { 454 argcheck(insn.a1.empty && insn.a2.empty); 455 passAct(1, 0x07, insn); 456 } 457 458 /** 459 * dad (0x09 + 16 bit register offset) 460 */ 461 static void dad(i80 insn) 462 { 463 argcheck(!insn.a1.empty && insn.a2.empty); 464 passAct(1, 0x09 + regMod16(insn), insn); 465 } 466 467 /** 468 * ldax (0x0a + 16 bit register offset) 469 */ 470 static void ldax(i80 insn) 471 { 472 argcheck(!insn.a1.empty && insn.a2.empty); 473 if (insn.a1 == "b") 474 passAct(1, 0x0a, insn); 475 else if (insn.a1 == "d") 476 passAct(1, 0x1a, insn); 477 else 478 err("ldax only takes b or d"); 479 } 480 481 /** 482 * dcx (0x0b + 16 bit register offset) 483 */ 484 static void dcx(i80 insn) 485 { 486 argcheck(!insn.a1.empty && insn.a2.empty); 487 passAct(1, 0x0b + regMod16(insn), insn); 488 } 489 490 /** 491 * rrc (0x0f) 492 */ 493 static void rrc(i80 insn) 494 { 495 argcheck(insn.a1.empty && insn.a2.empty); 496 passAct(1, 0x0f, insn); 497 } 498 499 /** 500 * ral (0x17) 501 */ 502 static void ral(i80 insn) 503 { 504 argcheck(insn.a1.empty && insn.a2.empty); 505 passAct(1, 0x17, insn); 506 } 507 508 /** 509 * rar (0x1f) 510 */ 511 static void rar(i80 insn) 512 { 513 argcheck(insn.a1.empty && insn.a2.empty); 514 passAct(1, 0x1f, insn); 515 } 516 517 /** 518 * shld (0x22) 519 */ 520 static void shld(i80 insn) 521 { 522 argcheck(!insn.a1.empty && insn.a2.empty); 523 passAct(3, 0x22, insn); 524 a16(insn); 525 } 526 527 /** 528 * daa (0x27) 529 */ 530 static void daa(i80 insn) 531 { 532 argcheck(insn.a1.empty && insn.a2.empty); 533 passAct(1, 0x27, insn); 534 imm(insn, IMM16); 535 } 536 537 /** 538 * lhld (0x2a) 539 */ 540 static void lhld(i80 insn) 541 { 542 argcheck(!insn.a1.empty && insn.a2.empty); 543 passAct(3, 0x2a, insn); 544 a16(insn); 545 } 546 547 /** 548 * cma (0x2f) 549 */ 550 static void cma(i80 insn) 551 { 552 argcheck(insn.a1.empty && insn.a2.empty); 553 passAct(1, 0x2f, insn); 554 } 555 556 /** 557 * sta (0x32) 558 */ 559 static void sta(i80 insn) 560 { 561 argcheck(!insn.a1.empty && insn.a2.empty); 562 passAct(3, 0x32, insn); 563 a16(insn); 564 } 565 566 /** 567 * stc (0x37) 568 */ 569 static void stc(i80 insn) 570 { 571 argcheck(insn.a1.empty && insn.a2.empty); 572 passAct(1, 0x37, insn); 573 } 574 575 /** 576 * lda (0x3a) 577 */ 578 static void lda(i80 insn) 579 { 580 argcheck(!insn.a1.empty && insn.a2.empty); 581 passAct(3, 0x3a, insn); 582 a16(insn); 583 } 584 585 /** 586 * cmc (0x3f) 587 */ 588 static void cmc(i80 insn) 589 { 590 argcheck(insn.a1.empty && insn.a2.empty); 591 passAct(1, 0x3f, insn); 592 } 593 594 /** 595 * mov (0x40 + (8-bit register offset << 3) + 8-bit register offset 596 * We allow mov m, m (0x76) 597 * But that will result in HLT. 598 */ 599 static void mov(i80 insn) 600 { 601 argcheck(!insn.a1.empty && !insn.a2.empty); 602 passAct(1, 0x40 + (regMod8(insn.a1) << 3) + regMod8(insn.a2), insn); 603 } 604 605 /** 606 * hlt (0x76) 607 */ 608 static void hlt(i80 insn) 609 { 610 argcheck(insn.a1.empty && insn.a2.empty); 611 passAct(1, 0x76, insn); 612 } 613 614 /** 615 * add (0x80 + 8-bit register offset) 616 */ 617 static void add(i80 insn) 618 { 619 argcheck(!insn.a1.empty && insn.a2.empty); 620 passAct(1, 0x80 + regMod8(insn.a1), insn); 621 } 622 623 /** 624 * adc (0x88 + 8-bit register offset) 625 */ 626 static void adc(i80 insn) 627 { 628 argcheck(!insn.a1.empty && insn.a2.empty); 629 passAct(1, 0x88 + regMod8(insn.a1), insn); 630 } 631 632 /** 633 * sub (0x90 + 8-bit register offset) 634 */ 635 static void sub(i80 insn) 636 { 637 argcheck(!insn.a1.empty && insn.a2.empty); 638 passAct(1, 0x90 + regMod8(insn.a1), insn); 639 } 640 641 /** 642 * sbb (0x98 + 8-bit register offset) 643 */ 644 static void sbb(i80 insn) 645 { 646 argcheck(!insn.a1.empty && insn.a2.empty); 647 passAct(1, 0x98 + regMod8(insn.a1), insn); 648 } 649 650 /** 651 * ana (0xa0 + 8-bit register offset) 652 */ 653 static void ana(i80 insn) 654 { 655 argcheck(!insn.a1.empty && insn.a2.empty); 656 passAct(1, 0xa0 + regMod8(insn.a1), insn); 657 } 658 659 /** 660 * xra (0xa8 + 8-bit register offset) 661 */ 662 static void xra(i80 insn) 663 { 664 argcheck(!insn.a1.empty && insn.a2.empty); 665 passAct(1, 0xa8 + regMod8(insn.a1), insn); 666 } 667 668 /** 669 * ora (0xb0 + 8-bit register offset) 670 */ 671 static void ora(i80 insn) 672 { 673 argcheck(!insn.a1.empty && insn.a2.empty); 674 passAct(1, 0xb0 + regMod8(insn.a1), insn); 675 } 676 677 /** 678 * cmp (0xb8 + 8-bit register offset) 679 */ 680 static void cmp(i80 insn) 681 { 682 argcheck(!insn.a1.empty && insn.a2.empty); 683 passAct(1, 0xb8 + regMod8(insn.a1), insn); 684 } 685 686 /** 687 * rnz (0xc0) 688 */ 689 static void rnz(i80 insn) 690 { 691 argcheck(insn.a1.empty && insn.a2.empty); 692 passAct(1, 0xc0, insn); 693 } 694 695 /** 696 * pop (0xc1 + 16 bit register offset) 697 */ 698 static void pop(i80 insn) 699 { 700 argcheck(!insn.a1.empty && insn.a2.empty); 701 passAct(1, 0xc1 + regMod16(insn), insn); 702 } 703 704 /** 705 * jnz (0xc2) 706 */ 707 static void jnz(i80 insn) 708 { 709 argcheck(!insn.a1.empty && insn.a2.empty); 710 passAct(3, 0xc2, insn); 711 a16(insn); 712 } 713 714 /** 715 * jmp (0xc3) 716 */ 717 static void jmp(i80 insn) 718 { 719 argcheck(!insn.a1.empty && insn.a2.empty); 720 passAct(3, 0xc3, insn); 721 a16(insn); 722 } 723 724 /** 725 * cnz (0xc4) 726 */ 727 static void cnz(i80 insn) 728 { 729 argcheck(!insn.a1.empty && insn.a2.empty); 730 passAct(3, 0xc4, insn); 731 a16(insn); 732 } 733 734 /** 735 * push (0xc5 + 16 bit register offset) 736 */ 737 static void push(i80 insn) 738 { 739 argcheck(!insn.a1.empty && insn.a2.empty); 740 passAct(1, 0xc5 + regMod16(insn), insn); 741 } 742 743 /** 744 * adi (0xc6) 745 */ 746 static void adi(i80 insn) 747 { 748 argcheck(!insn.a1.empty && insn.a2.empty); 749 passAct(2, 0xc6, insn); 750 imm(insn, IMM8); 751 } 752 753 /** 754 * rst (0xc7 + offset) 755 */ 756 static void rst(i80 insn) 757 { 758 argcheck(!insn.a1.empty && insn.a2.empty); 759 auto offset = to!int(insn.a1, 10); 760 if (offset >= 0 && offset <= 7) 761 passAct(1, 0xc7 + (offset * 8), insn); 762 else 763 err("invalid reset vector: " ~ to!string(offset)); 764 } 765 766 /** 767 * rz (0xc8) 768 */ 769 static void rz(i80 insn) 770 { 771 argcheck(insn.a1.empty && insn.a2.empty); 772 passAct(1, 0xc8, insn); 773 } 774 775 /** 776 * jz (0xca) 777 */ 778 static void jz(i80 insn) 779 { 780 argcheck(!insn.a1.empty && insn.a2.empty); 781 passAct(3, 0xca, insn); 782 a16(insn); 783 } 784 785 /** 786 * cz (0xcc) 787 */ 788 static void cz(i80 insn) 789 { 790 argcheck(!insn.a1.empty && insn.a2.empty); 791 passAct(3, 0xcc, insn); 792 a16(insn); 793 } 794 795 /** 796 * call (0xcd) 797 */ 798 static void call(i80 insn) 799 { 800 argcheck(!insn.a1.empty && insn.a2.empty); 801 passAct(3, 0xcd, insn); 802 a16(insn); 803 } 804 805 /** 806 * aci (0xce) 807 */ 808 static void aci(i80 insn) 809 { 810 argcheck(!insn.a1.empty && insn.a2.empty); 811 passAct(2, 0xce, insn); 812 imm(insn, IMM8); 813 } 814 815 /** 816 * rnc (0xd0) 817 */ 818 static void rnc(i80 insn) 819 { 820 argcheck(insn.a1.empty && insn.a2.empty); 821 passAct(1, 0xd0, insn); 822 } 823 824 /** 825 * jnc (0xd2) 826 */ 827 static void jnc(i80 insn) 828 { 829 argcheck(!insn.a1.empty && insn.a2.empty); 830 passAct(3, 0xd2, insn); 831 a16(insn); 832 } 833 834 /** 835 * out (0xd3) 836 */ 837 static void i80_out(i80 insn) 838 { 839 argcheck(!insn.a1.empty && insn.a2.empty); 840 passAct(2, 0xd3, insn); 841 imm(insn, IMM8); 842 } 843 844 /** 845 * cnc (0xd4) 846 */ 847 static void cnc(i80 insn) 848 { 849 argcheck(!insn.a1.empty && insn.a2.empty); 850 passAct(3, 0xd4, insn); 851 a16(insn); 852 } 853 854 /** 855 * sui (0xd6) 856 */ 857 static void sui(i80 insn) 858 { 859 argcheck(!insn.a1.empty && insn.a2.empty); 860 passAct(2, 0xd6, insn); 861 imm(insn, IMM8); 862 } 863 864 /** 865 * rc (0xd8) 866 */ 867 static void rc(i80 insn) 868 { 869 argcheck(insn.a1.empty && insn.a2.empty); 870 passAct(1, 0xd8, insn); 871 } 872 873 /** 874 * jc (0xda) 875 */ 876 static void jc(i80 insn) 877 { 878 argcheck(!insn.a1.empty && insn.a2.empty); 879 passAct(3, 0xda, insn); 880 a16(insn); 881 } 882 883 /** 884 * in (0xdb) 885 */ 886 static void i80_in(i80 insn) 887 { 888 argcheck(!insn.a1.empty && insn.a2.empty); 889 passAct(2, 0xdb, insn); 890 imm(insn, IMM8); 891 } 892 893 /** 894 * cc (0xdc) 895 */ 896 static void cc(i80 insn) 897 { 898 argcheck(!insn.a1.empty && insn.a2.empty); 899 passAct(3, 0xdc, insn); 900 a16(insn); 901 } 902 903 /** 904 * sbi (0xde) 905 */ 906 static void sbi(i80 insn) 907 { 908 argcheck(!insn.a1.empty && insn.a2.empty); 909 passAct(2, 0xde, insn); 910 imm(insn, IMM8); 911 } 912 913 /** 914 * rpo (0xe0) 915 */ 916 static void rpo(i80 insn) 917 { 918 argcheck(insn.a1.empty && insn.a2.empty); 919 passAct(1, 0xe0, insn); 920 } 921 922 /** 923 * jpo (0xe2) 924 */ 925 static void jpo(i80 insn) 926 { 927 argcheck(!insn.a1.empty && insn.a2.empty); 928 passAct(3, 0xe2, insn); 929 a16(insn); 930 } 931 932 /** 933 * xthl (0xe3) 934 */ 935 static void xthl(i80 insn) 936 { 937 argcheck(insn.a1.empty && insn.a2.empty); 938 passAct(1, 0xe3, insn); 939 } 940 941 /** 942 * cpo (0xe4) 943 */ 944 static void cpo(i80 insn) 945 { 946 argcheck(!insn.a1.empty && insn.a2.empty); 947 passAct(3, 0xe4, insn); 948 a16(insn); 949 } 950 951 /** 952 * ani (0xe6) 953 */ 954 static void ani(i80 insn) 955 { 956 argcheck(!insn.a1.empty && insn.a2.empty); 957 passAct(2, 0xe6, insn); 958 imm(insn, IMM8); 959 } 960 961 /** 962 * rpe (0xe8) 963 */ 964 static void rpe(i80 insn) 965 { 966 argcheck(insn.a1.empty && insn.a2.empty); 967 passAct(1, 0xe8, insn); 968 } 969 970 /** 971 * pchl (0xe9) 972 */ 973 static void pchl(i80 insn) 974 { 975 argcheck(insn.a1.empty && insn.a2.empty); 976 passAct(1, 0xe9, insn); 977 } 978 979 /** 980 * jpe (0xea) 981 */ 982 static void jpe(i80 insn) 983 { 984 argcheck(!insn.a1.empty && insn.a2.empty); 985 passAct(3, 0xea, insn); 986 a16(insn); 987 } 988 989 /** 990 * xchg (0xeb) 991 */ 992 static void xchg(i80 insn) 993 { 994 argcheck(insn.a1.empty && insn.a2.empty); 995 passAct(1, 0xeb, insn); 996 } 997 998 /** 999 * cpe (0xec) 1000 */ 1001 static void cpe(i80 insn) 1002 { 1003 argcheck(!insn.a1.empty && insn.a2.empty); 1004 passAct(3, 0xec, insn); 1005 a16(insn); 1006 } 1007 1008 /** 1009 * xri (0xee) 1010 */ 1011 static void xri(i80 insn) 1012 { 1013 argcheck(!insn.a1.empty && insn.a2.empty); 1014 passAct(2, 0xee, insn); 1015 imm(insn, IMM8); 1016 } 1017 1018 /** 1019 * rp (0xf0) 1020 */ 1021 static void rp(i80 insn) 1022 { 1023 argcheck(insn.a1.empty && insn.a2.empty); 1024 passAct(1, 0xf0, insn); 1025 } 1026 1027 /** 1028 * jp (0xf2) 1029 */ 1030 static void jp(i80 insn) 1031 { 1032 argcheck(!insn.a1.empty && insn.a2.empty); 1033 passAct(3, 0xf2, insn); 1034 a16(insn); 1035 } 1036 1037 /** 1038 * di (0xf3) 1039 */ 1040 static void di(i80 insn) 1041 { 1042 argcheck(insn.a1.empty && insn.a2.empty); 1043 passAct(1, 0xf3, insn); 1044 } 1045 1046 /** 1047 * cp (0xf4) 1048 */ 1049 static void cp(i80 insn) 1050 { 1051 argcheck(!insn.a1.empty && insn.a2.empty); 1052 passAct(3, 0xf4, insn); 1053 a16(insn); 1054 } 1055 1056 /** 1057 * ori (0xf6) 1058 */ 1059 static void ori(i80 insn) 1060 { 1061 argcheck(!insn.a1.empty && insn.a2.empty); 1062 passAct(2, 0xf6, insn); 1063 imm(insn, IMM8); 1064 } 1065 1066 /** 1067 * rm (0xf8) 1068 */ 1069 static void rm(i80 insn) 1070 { 1071 argcheck(insn.a1.empty && insn.a2.empty); 1072 passAct(1, 0xf8, insn); 1073 } 1074 1075 /** 1076 * sphl (0xf9) 1077 */ 1078 static void sphl(i80 insn) 1079 { 1080 argcheck(insn.a1.empty && insn.a2.empty); 1081 passAct(1, 0xf9, insn); 1082 } 1083 1084 /** 1085 * jm (0xfa) 1086 */ 1087 static void jm(i80 insn) 1088 { 1089 argcheck(!insn.a1.empty && insn.a2.empty); 1090 passAct(3, 0xfa, insn); 1091 a16(insn); 1092 } 1093 1094 /** 1095 * ei (0xfb) 1096 */ 1097 static void ei(i80 insn) 1098 { 1099 argcheck(insn.a1.empty && insn.a2.empty); 1100 passAct(1, 0xfb, insn); 1101 } 1102 1103 /** 1104 * cm (0xfc) 1105 */ 1106 static void cm(i80 insn) 1107 { 1108 argcheck(!insn.a1.empty && insn.a2.empty); 1109 passAct(3, 0xfc, insn); 1110 a16(insn); 1111 } 1112 1113 /** 1114 * cpi (0xfe) 1115 */ 1116 static void cpi(i80 insn) 1117 { 1118 argcheck(!insn.a1.empty && insn.a2.empty); 1119 passAct(2, 0xfe, insn); 1120 imm(insn, IMM8); 1121 } 1122 1123 /** 1124 * Define a constant. 1125 */ 1126 static void equ(i80 insn) 1127 { 1128 if (insn.lab.empty) 1129 err("must have a label in equ statement"); 1130 1131 if (insn.a1[insn.a1.length - 1] != 'h') 1132 err("number must end with 'h'"); 1133 auto a = to!ushort(chop(insn.a1), 16); 1134 if (pass == 1) 1135 addsym(insn.lab, a); 1136 } 1137 1138 /** 1139 * Place a byte. 1140 */ 1141 static void db(i80 insn) 1142 { 1143 argcheck(!insn.a1.empty && insn.a2.empty); 1144 if (isDigit(insn.a1[0]) && insn.a1.length > 1) { 1145 if (insn.a1[insn.a1.length - 1] != 'h') 1146 err("number must end with 'h'"); 1147 passAct(1, to!ubyte(chop(insn.a1), 16), insn); 1148 } else { 1149 if (pass == 1) { 1150 if (!insn.lab.empty) 1151 addsym(insn.lab, addr); 1152 addr += insn.a1.length; 1153 } else { 1154 for (size_t i = 0; i < insn.a1.length; i++) 1155 output ~= cast(ubyte)insn.a1[i]; 1156 } 1157 } 1158 } 1159 1160 /** 1161 * Force updated the address counter. 1162 */ 1163 static void org(i80 insn) 1164 { 1165 argcheck(insn.lab.empty && !insn.a1.empty && insn.a2.empty); 1166 if (isDigit(insn.a1[0])) { 1167 if (insn.a1[insn.a1.length - 1] != 'h') 1168 err("number must end with 'h'"); 1169 if (pass == 1) 1170 addr = to!ushort(chop(insn.a1), 16); 1171 } else { 1172 err("org must take a number"); 1173 } 1174 } 1175 1176 /** 1177 * Return the 16 bit register offset. 1178 */ 1179 static int regMod16(i80 insn) 1180 { 1181 if (insn.a1 == "b") { 1182 return 0x00; 1183 } else if (insn.a1 == "d") { 1184 return 0x10; 1185 } else if (insn.a1 == "h") { 1186 return 0x20; 1187 } else if (insn.a1 == "psw") { 1188 if (insn.op == "pop" || insn.op == "push") 1189 return 0x30; 1190 else 1191 err("psw may not be used with " ~ insn.op); 1192 } else if (insn.a1 == "sp") { 1193 if (insn.op != "pop" && insn.op != "push") 1194 return 0x30; 1195 else 1196 err("sp may not be used with " ~ insn.op); 1197 } else { 1198 err("invalid register for " ~ insn.op); 1199 } 1200 1201 /* This will never be reached, but quiets gdc. */ 1202 return 0; 1203 } 1204 1205 /** 1206 * Return the 8 bit register offset. 1207 */ 1208 static int regMod8(string reg) 1209 { 1210 if (reg == "b") 1211 return 0x00; 1212 else if (reg == "c") 1213 return 0x01; 1214 else if (reg == "d") 1215 return 0x02; 1216 else if (reg == "e") 1217 return 0x03; 1218 else if (reg == "h") 1219 return 0x04; 1220 else if (reg == "l") 1221 return 0x05; 1222 else if (reg == "m") 1223 return 0x06; 1224 else if (reg == "a") 1225 return 0x07; 1226 else 1227 err("invalid register " ~ reg); 1228 1229 /* This will never be reached, but quiets gdc. */ 1230 return 0; 1231 } 1232 1233 /** 1234 * Get an 8 or 16 bit immediate. 1235 */ 1236 static void imm(i80 insn, int immtype) 1237 { 1238 ushort dig; 1239 string check; 1240 bool found = false; 1241 1242 if (insn.op == "lxi" || insn.op == "mvi") 1243 check = insn.a2; 1244 else 1245 check = insn.a1; 1246 1247 if (isDigit(check[0])) { 1248 if (check[check.length - 1] != 'h') 1249 err("number must end with 'h'"); 1250 dig = to!ushort(chop(check), 16); 1251 } else { 1252 for (size_t i = 0; i < stab.length; i++) { 1253 if (check == stab[i].name) { 1254 dig = stab[i].value; 1255 found = true; 1256 break; 1257 } 1258 } 1259 if (pass == 2) { 1260 if (!found) 1261 err("label " ~ check ~ " not defined"); 1262 } 1263 } 1264 1265 if (pass == 2) { 1266 output ~= cast(ubyte)(dig & 0xff); 1267 if (immtype == IMM16) 1268 output ~= cast(ubyte)((dig >> 8) & 0xff); 1269 } 1270 } 1271 1272 /** 1273 * Get a 16-bit address. 1274 */ 1275 static void a16(i80 insn) 1276 { 1277 ushort dig; 1278 bool found = false; 1279 1280 if (isDigit(insn.a1[0])) { 1281 if (insn.a1[insn.a1.length - 1] != 'h') 1282 err("number must end with 'h'"); 1283 dig = to!ushort(chop(insn.a1), 16); 1284 } else { 1285 for (size_t i = 0; i < stab.length; i++) { 1286 if (insn.a1 == stab[i].name) { 1287 dig = stab[i].value; 1288 found = true; 1289 break; 1290 } 1291 } 1292 if (pass == 2) { 1293 if (!found) 1294 err("label " ~ insn.a1 ~ " not defined"); 1295 } 1296 } 1297 1298 if (pass == 2) { 1299 output ~= cast(ubyte)(dig & 0xff); 1300 output ~= cast(ubyte)((dig >> 8) & 0xff); 1301 } 1302 } 1303 1304 /** 1305 * Nice error messages. 1306 */ 1307 static void err(string msg) 1308 { 1309 writeln("a80: " ~ to!string(line + 1) ~ ": " ~ msg); 1310 enforce(0); 1311 } 1312 1313 /** 1314 * Check arguments. 1315 */ 1316 static void argcheck(bool passed) 1317 { 1318 if (passed == false) 1319 err("arguments not correct for opcode"); 1320 }