-
+ 5B25235B8644D82E985ED6CC354E5E6E0D94AAAF0D0B5A7B33D8A5586CF67A90F13885398E5C10B935C9EE991B1CC720AE9B832DFF9961D6090CF5E17A0445B9
m/mipsinst/i_instrs.asm
(0 . 0)(1 . 1123)
2355 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2356 ;; ;;
2357 ;; This file is part of 'M', a MIPS system emulator. ;;
2358 ;; ;;
2359 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
2360 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
2361 ;; ;;
2362 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
2363 ;; distribute this software ; Should you use this software for any purpose, ;;
2364 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
2365 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
2366 ;; continue doing so for the indefinite future. In any case, please ;;
2367 ;; always : read and understand any software ; verify any PGP signatures ;;
2368 ;; that you use - for any purpose. ;;
2369 ;; ;;
2370 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
2371 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2372
2373 ;; TODO: 1) Trap for ADDI (gcc 4.8.1 doesn't appear to use, but it exists...)
2374 ;; 2) Tests!!!
2375
2376 ;------------------------
2377 ; I-Type Instructions : |
2378 ;------------------------
2379
2380 ;-----------------------------------------------------------------------------
2381 section .rodata
2382 align GRAIN, db 0x90
2383 _I_Table:
2384 A32 _i_000000 ; 0x00 : All R-Type Instructions
2385 A32 _i_000001 ; 0x01 : bltz, bgez, bltzl, bgezl, bltzal, bgezal
2386 A32 _i_j ; 0x02 : j (000010??????????????????????????)
2387 A32 _i_jal ; 0x03 : jal (000011??????????????????????????)
2388 A32 _i_beq ; 0x04 : beq (000100??????????????????????????)
2389 A32 _i_bne ; 0x05 : bne (000101??????????????????????????)
2390 A32 _i_blez ; 0x06 : blez (000110??????????????????????????)
2391 A32 _i_bgtz ; 0x07 : bgtz (000111??????????????????????????)
2392 A32 _i_addi ; 0x08 : addi (001000??????????????????????????)
2393 A32 _i_addiu ; 0x09 : addiu (001001??????????????????????????)
2394 A32 _i_slti ; 0x0a : slti (001010??????????????????????????)
2395 A32 _i_sltiu ; 0x0b : sltiu (001011??????????????????????????)
2396 A32 _i_andi ; 0x0c : andi (001100??????????????????????????)
2397 A32 _i_ori ; 0x0d : ori (001101??????????????????????????)
2398 A32 _i_xori ; 0x0e : xori (001110??????????????????????????)
2399 A32 _i_lui ; 0x0f : lui (001111??????????????????????????)
2400 A32 _i_010000 ; 0x10 : mfc0, mtc0, tlbwi, tlbwr, tlbp, eret, wait
2401 A32 _bad ; 0x11 : UNDEFINED
2402 A32 _bad ; 0x12 : UNDEFINED
2403 A32 _bad ; 0x13 : UNDEFINED
2404 A32 _i_beql ; 0x14 : beql (010100??????????????????????????)
2405 A32 _i_bnel ; 0x15 : bnel (010101??????????????????????????)
2406 A32 _i_blezl ; 0x16 : blezl (010110??????????????????????????)
2407 A32 _i_bgtzl ; 0x17 : bgtzl (010111?????00000????????????????)
2408 A32 _bad ; 0x18 : UNDEFINED
2409 A32 _bad ; 0x19 : UNDEFINED
2410 A32 _bad ; 0x1a : UNDEFINED
2411 A32 _bad ; 0x1b : UNDEFINED
2412 A32 _i_mul ; 0x1c : mul (011100???????????????00000000010)
2413 A32 _bad ; 0x1d : UNDEFINED
2414 A32 _bad ; 0x1e : UNDEFINED
2415 A32 _bad ; 0x1f : UNDEFINED
2416 A32 _i_lb ; 0x20 : lb (100000??????????????????????????)
2417 A32 _i_lh ; 0x21 : lh (100001??????????????????????????)
2418 A32 _i_lwl ; 0x22 : lwl (100010??????????????????????????)
2419 A32 _i_lw ; 0x23 : lw (100011??????????????????????????)
2420 A32 _i_lbu ; 0x24 : lbu (100100??????????????????????????)
2421 A32 _i_lhu ; 0x25 : lhu (100101??????????????????????????)
2422 A32 _i_lwr ; 0x26 : lwr (100110??????????????????????????)
2423 A32 _bad ; 0x27 : UNDEFINED
2424 A32 _i_sb ; 0x28 : sb (101000??????????????????????????)
2425 A32 _i_sh ; 0x29 : sh (101001??????????????????????????)
2426 A32 _i_swl ; 0x2a : swl (101010??????????????????????????)
2427 A32 _i_sw ; 0x2b : sw (101011??????????????????????????)
2428 A32 _bad ; 0x2c : UNDEFINED
2429 A32 _bad ; 0x2d : UNDEFINED
2430 A32 _i_swr ; 0x2e : swr (101110??????????????????????????)
2431 A32 _i_cache ; 0x2f : cache (101111??????????????????????????)
2432 A32 _i_ll ; 0x30 : ll (110000??????????????????????????)
2433 A32 _bad ; 0x31 : UNDEFINED
2434 A32 _bad ; 0x32 : UNDEFINED
2435 A32 _i_pref ; 0x33 : pref (110011??????????????????????????)
2436 A32 _bad ; 0x34 : UNDEFINED
2437 A32 _bad ; 0x35 : UNDEFINED
2438 A32 _bad ; 0x36 : UNDEFINED
2439 A32 _bad ; 0x37 : UNDEFINED
2440 A32 _i_sc ; 0x38 : sc (111000??????????????????????????)
2441 A32 _bad ; 0x39 : UNDEFINED
2442 A32 _bad ; 0x3a : UNDEFINED
2443 A32 _bad ; 0x3b : UNDEFINED
2444 A32 _bad ; 0x3c : UNDEFINED
2445 A32 _bad ; 0x3d : UNDEFINED
2446 A32 _bad ; 0x3e : UNDEFINED
2447 A32 _bad ; 0x3f : UNDEFINED
2448 ;-----------------------------------------------------------------------------
2449 align GRAIN, db 0x90
2450 _MFC0_Table:
2451 A32 _mfc0_r00 ; 0x00
2452 A32 _mfc0_r01 ; 0x01
2453 A32 _mfc0_r02 ; 0x02
2454 A32 _mfc0_r03 ; 0x03
2455 A32 _mfc0_r04 ; 0x04
2456 A32 _mfc0_r05 ; 0x05
2457 A32 _mfc0_r06 ; 0x06
2458 A32 _mfc0_r07 ; 0x07
2459 A32 _mfc0_r08 ; 0x08
2460 A32 _mfc0_r09 ; 0x09
2461 A32 _mfc0_r10 ; 0x0a
2462 A32 _mfc0_r11 ; 0x0b
2463 A32 _mfc0_r12 ; 0x0c
2464 A32 _mfc0_r13 ; 0x0d
2465 A32 _mfc0_r14 ; 0x0e
2466 A32 _mfc0_r15 ; 0x0f
2467 A32 _mfc0_r16 ; 0x10
2468 A32 _mfc0_r17 ; 0x11
2469 A32 _mfc0_r18 ; 0x12
2470 A32 _mfc0_r19 ; 0x13
2471 A32 _mfc0_r20 ; 0x14
2472 A32 _mfc0_r21 ; 0x15
2473 A32 _mfc0_r22 ; 0x16
2474 A32 _mfc0_r23 ; 0x17
2475 A32 _mfc0_r24 ; 0x18
2476 A32 _mfc0_r25 ; 0x19
2477 A32 _mfc0_r26 ; 0x1a
2478 A32 _mfc0_r27 ; 0x1b
2479 A32 _mfc0_r28 ; 0x1c
2480 A32 _mfc0_r29 ; 0x1d
2481 A32 _mfc0_r30 ; 0x1e
2482 A32 _mfc0_r31 ; 0x1f
2483 ;-----------------------------------------------------------------------------
2484 align GRAIN, db 0x90
2485 _MTC0_Table:
2486 A32 _mtc0_r00 ; 0x00
2487 A32 _mtc0_r01 ; 0x01
2488 A32 _mtc0_r02 ; 0x02
2489 A32 _mtc0_r03 ; 0x03
2490 A32 _mtc0_r04 ; 0x04
2491 A32 _mtc0_r05 ; 0x05
2492 A32 _mtc0_r06 ; 0x06
2493 A32 _mtc0_r07 ; 0x07
2494 A32 _mtc0_r08 ; 0x08
2495 A32 _mtc0_r09 ; 0x09
2496 A32 _mtc0_r10 ; 0x0a
2497 A32 _mtc0_r11 ; 0x0b
2498 A32 _mtc0_r12 ; 0x0c
2499 A32 _mtc0_r13 ; 0x0d
2500 A32 _mtc0_r14 ; 0x0e
2501 A32 _mtc0_r15 ; 0x0f
2502 A32 _mtc0_r16 ; 0x10
2503 A32 _mtc0_r17 ; 0x11
2504 A32 _mtc0_r18 ; 0x12
2505 A32 _mtc0_r19 ; 0x13
2506 A32 _mtc0_r20 ; 0x14
2507 A32 _mtc0_r21 ; 0x15
2508 A32 _mtc0_r22 ; 0x16
2509 A32 _mtc0_r23 ; 0x17
2510 A32 _mtc0_r24 ; 0x18
2511 A32 _mtc0_r25 ; 0x19
2512 A32 _mtc0_r26 ; 0x1a
2513 A32 _mtc0_r27 ; 0x1b
2514 A32 _mtc0_r28 ; 0x1c
2515 A32 _mtc0_r29 ; 0x1d
2516 A32 _mtc0_r30 ; 0x1e
2517 A32 _mtc0_r31 ; 0x1f
2518 ;-----------------------------------------------------------------------------
2519
2520 section .text
2521
2522 ;------------------------
2523 ; Invalid Instruction : |
2524 ;------------------------
2525 align GRAIN, db 0x90
2526 _bad:
2527 SetEXC EXC_RI ; Set the EXC_RI Exception
2528 jmp _Handle_Exception ; Go straight to exception handler.
2529 ;-----------------------------------------------------------------------------
2530
2531 ;-----------------------------------------------------------------------------
2532 ; Eat 000000?????????????????????????? (R-Type) Instructions:
2533 ;-----------------------------------------------------------------------------
2534 align GRAIN, db 0x90
2535 _i_000000:
2536 mov eax, r_I ; Get the original instruction :
2537 and eax, 0x3F ; Get funct field, (lower 6 bits) ;
2538 JTABLE eax, _R_Table ; Dispatch on funct-field via R-Table.
2539 ;-----------------------------------------------------------------------------
2540
2541 ;-----------------------------------------------------------------------------
2542 ; Eat 000001?????QQQQQ???????????????? Branch Instructions :
2543 ; i.e. bltz, bgez, bltzl, bgezl, bltzal, bgezal
2544 ;-----------------------------------------------------------------------------
2545 align GRAIN, db 0x90
2546 _i_000001:
2547 mov eax, r_I ; Get the original instruction :
2548 shr eax, 16 ; Get the 5-bit field QQQQQ
2549 and eax, 0x1F ; which distinguishes these;
2550 JTABLE eax, _B_Table ; Dispatch via B-Table.
2551 ;-----------------------------------------------------------------------------
2552
2553 ;-----------------------------------------------------------------------------
2554 ; Eat 010000?????????????????????????? Misc. Instructions :
2555 ; mfc0, mtc0, tlbwi, tlbwr, tlbp, eret, wait
2556 ; PRIVILEGED (permitted in Kernel Mode only.)
2557 ;-----------------------------------------------------------------------------
2558 align GRAIN, db 0x90
2559 _i_010000:
2560 PRIVILEGED ; Permitted in Kernel Mode only.
2561 mov eax, r_I ; Get the original instruction :
2562 shr eax, 5 ; Get the top 27 bits
2563 cmp eax, 0x2100000 ; Equal 010000100000000000000000000..?
2564 je _tlbwi_tlbwr_tlbp_eret ; 010000100000000000000000000QQQQQ
2565 ;; At this point, we have either mfc0, mtc0, wait, or a bad instr:
2566 shr eax, 16 ; We already shifted by 5, so now 21:
2567 cmp eax, 0x200 ; ... are they equal to 0b01000000000 ?
2568 je _m_mfc0 ; mfc0 (01000000000?????????????????????)
2569 cmp eax, 0x204 ; ... are they equal to 0b01000000100 ?
2570 je _m_mtc0 ; mtc0 (01000000100?????????????????????)
2571 ;; Now determine if it is 'wait' (0100001???????????????????100000) :
2572 mov eax, r_I ; Get the original instruction :
2573 and eax, 0xFE00003F ; Get top 7 bits and bottom 6 bits only
2574 cmp eax, 0x42000020 ; Top must be 0b0100001, bottom 0b100000
2575 je _m_wait ; wait (0100001???????????????????100000)
2576 ;; Now, if it wasn't the 'wait' instruction, we must then have a turd:
2577 jmp _bad ; If we're here : undefined inst.
2578 ;-----------------------------------------------------------------------------
2579
2580 ;-----------------------------------------------------------------------------
2581 ; Eat 010000100000000000000000000QQQQQ Instructions (via _i_010000) :
2582 ; tlbwi, tlbwr, tlbp, eret
2583 ;-----------------------------------------------------------------------------
2584 align GRAIN, db 0x90
2585 _tlbwi_tlbwr_tlbp_eret:
2586 mov eax, r_I ; Get the original instruction :
2587 and eax, 0x1F ; Get the the 5-bit field QQQQQ from it
2588 JTABLE eax, _M_Table ; Dispatch via M-Table.
2589 ;-----------------------------------------------------------------------------
2590
2591 ;-----------------------------------------------------------------------------
2592 ; J -- Jump.
2593 ; Jumps to the calculated address.
2594 ; Operation: PC = nPC; nPC = (PC & 0xF0000000) | (target << 2);
2595 ; Syntax: j target
2596 ; Encoding: 0000 10ii iiii iiii iiii iiii iiii iiii
2597 ;-----------------------------------------------------------------------------
2598 align GRAIN, db 0x90
2599 _i_j:
2600 JType ; load J Field (ii..iii << 2)
2601 mov nPC, PC ; nPC := PC
2602 and nPC, 0xF0000000 ; keep only top 4 bits of nPC, zero rest
2603 or nPC, JTarg ; nPC := nPC | ( target << 2 )
2604 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2605 jmp _end_cycle
2606 ;-----------------------------------------------------------------------------
2607
2608 ;-----------------------------------------------------------------------------
2609 ; JAL -- Jump and link.
2610 ; Jumps to the calculated address and stores the return address in $31.
2611 ; Operation: $31 = PC + 8 (or nPC + 4);
2612 ; PC = nPC;
2613 ; nPC = (PC & 0xF0000000) | (target << 2);
2614 ; Syntax: jal target
2615 ; Encoding: 0000 11ii iiii iiii iiii iiii iiii iiii
2616 ;-----------------------------------------------------------------------------
2617 align GRAIN, db 0x90
2618 _i_jal:
2619 JType ; load J Field (ii..iii << 2)
2620 mov TMP, PC ; TMP := PC
2621 add TMP, 0x8 ; TMP := TMP + 8
2622 mov R(31), TMP ; Regs[31] := TMP
2623 sub TMP, 0x8 ; TMP := TMP - 8
2624 and TMP, 0xF0000000 ; keep only top 4 bits of TMP, zero rest
2625 or TMP, JTarg ; TMP := TMP | ( target << 2 )
2626 mov nPC, TMP ; nPC := TMP
2627 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2628 jmp _end_cycle
2629 ;-----------------------------------------------------------------------------
2630
2631 ;-----------------------------------------------------------------------------
2632 ; BEQ -- Branch on equal.
2633 ; Branches if the two registers are equal.
2634 ; Operation: if $s == $t advance_pc(offset << 2));
2635 ; else advance_pc(4);
2636 ; Syntax: beq $s, $t, offset
2637 ; Encoding: 0001 00ss ssst tttt iiii iiii iiii iiii
2638 ;-----------------------------------------------------------------------------
2639 align GRAIN, db 0x90
2640 _i_beq:
2641 IType ; Load Imm, rS, rT Fields
2642 mov nPC, PC ; nPC := PC
2643 add nPC, 0x4 ; nPC := nPC + 4
2644 SX18_4N Imm ; Sign Extend Imm * 4
2645 mov TMP, R(rS) ; TMP := Regs[rS]
2646 cmp TMP, R(rT) ; CMP(TMP, Regs[rT])
2647 mov TMP, 0x4 ; TMP := 4
2648 cmove TMP, Imm ; If Regs[rS] = Regs[rT], TMP := Imm
2649 add nPC, TMP ; nPC := nPC + TMP
2650 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2651 jmp _end_cycle
2652 ;-----------------------------------------------------------------------------
2653
2654 ;-----------------------------------------------------------------------------
2655 ; BNE -- Branch on not equal.
2656 ; Branches if the two registers are not equal.
2657 ; Operation: if $s != $t advance_pc(offset << 2));
2658 ; else advance_pc(4);
2659 ; Syntax: bne $s, $t, offset
2660 ; Encoding: 0001 01ss ssst tttt iiii iiii iiii iiii
2661 ;-----------------------------------------------------------------------------
2662 align GRAIN, db 0x90
2663 _i_bne:
2664 IType ; Load Imm, rS, rT Fields
2665 mov nPC, PC ; nPC := PC
2666 add nPC, 0x4 ; nPC := nPC + 4
2667 SX18_4N Imm ; Sign Extend Imm * 4
2668 mov TMP, R(rS) ; TMP := Regs[rS]
2669 cmp TMP, R(rT) ; CMP(TMP, Regs[rT])
2670 mov TMP, 0x4 ; TMP := 4
2671 cmovne TMP, Imm ; If Regs[rS] != Regs[rT], TMP := Imm
2672 add nPC, TMP ; nPC := nPC + TMP
2673 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2674 jmp _end_cycle
2675 ;-----------------------------------------------------------------------------
2676
2677 ;-----------------------------------------------------------------------------
2678 ; BLEZ -- Branch on less than or equal to zero.
2679 ; Branches if the register is less than or equal to zero
2680 ; Operation: if $s <= 0 advance_pc(offset << 2));
2681 ; else advance_pc(4);
2682 ; Syntax: blez $s, offset
2683 ; Encoding: 0001 10ss sss0 0000 iiii iiii iiii iiii
2684 ;-----------------------------------------------------------------------------
2685 align GRAIN, db 0x90
2686 _i_blez:
2687 IType_I_S_Only ; load rS and Imm Fields
2688 mov nPC, PC ; nPC := PC
2689 add nPC, 0x4 ; nPC := nPC + 4
2690 SX18_4N Imm ; Sign Extend Imm * 4
2691 mov TMP, 0x4 ; TMP := 4
2692 cmp R(rS), 0 ; If Regs[rS] <= 0:
2693 cmovle TMP, Imm ; ... then TMP := Imm
2694 add nPC, TMP ; nPC := nPC + TMP
2695 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2696 jmp _end_cycle
2697 ;-----------------------------------------------------------------------------
2698
2699 ;-----------------------------------------------------------------------------
2700 ; BGTZ -- Branch on greater than zero.
2701 ; Branches if the register is greater than zero
2702 ; Operation: if $s > 0 advance_pc(offset << 2));
2703 ; else advance_pc(4);
2704 ; Syntax: bgtz $s, offset
2705 ; Encoding: 0001 11ss sss0 0000 iiii iiii iiii iiii
2706 ;-----------------------------------------------------------------------------
2707 align GRAIN, db 0x90
2708 _i_bgtz:
2709 IType_I_S_Only ; load rS and Imm Fields
2710 mov nPC, PC ; nPC := PC
2711 add nPC, 0x4 ; nPC := nPC + 4
2712 SX18_4N Imm ; Sign Extend Imm * 4
2713 mov TMP, 0x4 ; TMP := 4
2714 cmp R(rS), 0 ; If Regs[rS] > 0:
2715 cmovg TMP, Imm ; ... then TMP := Imm
2716 add nPC, TMP ; nPC := nPC + TMP
2717 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2718 jmp _end_cycle
2719 ;-----------------------------------------------------------------------------
2720
2721 ;-----------------------------------------------------------------------------
2722 ; ADDI -- Add immediate (with overflow).
2723 ; Adds a register and a sign-extended immediate value and stores the
2724 ; result in a register
2725 ; Operation: $t = $s + imm; advance_pc(4);
2726 ; Syntax: addi $t, $s, imm
2727 ; Encoding: 0010 00ss ssst tttt iiii iiii iiii iiii
2728 ;-----------------------------------------------------------------------------
2729 ; TODO: untested
2730 align GRAIN, db 0x90
2731 _i_addi:
2732 ; UNDONE_INST
2733 IType ; Load Imm, rS, rT Fields
2734 SX16 Imm ; Sign-extend the Imm offset
2735 mov TMP, R(rS) ; TMP := Regs[rS]
2736 add TMP, Imm ; TMP := TMP + Imm
2737 ; TODO: detect and trap overflow
2738 Wr_Reg rT, TMP ; Regs[rT] := TMP (result)
2739 jmp _end_cycle
2740 ;-----------------------------------------------------------------------------
2741
2742 ;-----------------------------------------------------------------------------
2743 ; ADDIU -- Add immediate unsigned (no overflow).
2744 ; Adds a register and a sign-extended immediate value and stores the
2745 ; result in a register
2746 ; Operation: $t = $s + imm; advance_pc(4);
2747 ; Syntax: addiu $t, $s, imm
2748 ; Encoding: 0010 01ss ssst tttt iiii iiii iiii iiii
2749 ;-----------------------------------------------------------------------------
2750 align GRAIN, db 0x90
2751 _i_addiu:
2752 IType ; Load Imm, rS, rT Fields
2753 SX16 Imm ; Sign-extend the Imm offset
2754 mov TMP, R(rS) ; TMP := Regs[rS]
2755 add TMP, Imm ; TMP := TMP + Imm
2756 Wr_Reg rT, TMP ; Regs[rT] := TMP (result)
2757 jmp _end_cycle
2758 ;-----------------------------------------------------------------------------
2759
2760 ;-----------------------------------------------------------------------------
2761 ; SLTI -- Set on less than immediate (signed).
2762 ; If $s is less than immediate, $t is set to one. It gets zero otherwise.
2763 ; Operation: if $s < imm $t = 1; advance_pc(4);
2764 ; else $t = 0; advance_pc(4);
2765 ; Syntax: slti $t, $s, imm
2766 ; Encoding: 0010 10ss ssst tttt iiii iiii iiii iiii
2767 ;-----------------------------------------------------------------------------
2768 align GRAIN, db 0x90
2769 _i_slti:
2770 IType ; Load Imm, rS, rT Fields
2771 SX16 Imm ; Sign-extend the Imm offset
2772 xor TMP, TMP ; Clear TMP
2773 cmp R(rS), Imm ; CMP(R(rS), Imm)
2774 setl TMP_LowByte ; if $s <(sgn) imm then TMP := 1; else 0
2775 Wr_Reg rT, TMP ; Regs[rT] := TMP (result)
2776 jmp _end_cycle
2777 ;-----------------------------------------------------------------------------
2778
2779 ;-----------------------------------------------------------------------------
2780 ; SLTIU -- Set on less than immediate unsigned.
2781 ; If $s is less than the unsigned immediate, $t is set to one.
2782 ; It gets zero otherwise.
2783 ; Operation: if $s < imm $t = 1; advance_pc(4);
2784 ; else $t = 0; advance_pc(4);
2785 ; Syntax: sltiu $t, $s, imm
2786 ; Encoding: 0010 11ss ssst tttt iiii iiii iiii iiii
2787 ;-----------------------------------------------------------------------------
2788 ; Apparently even here we sign-extend the immediate.
2789 align GRAIN, db 0x90
2790 _i_sltiu:
2791 IType ; Load Imm, rS, rT Fields
2792 SX16 Imm ; Sign-extend the Imm offset
2793 xor TMP, TMP ; Clear TMP
2794 cmp R(rS), Imm ; CMP(R(rS), Imm)
2795 setb TMP_LowByte ; if $s < imm then TMP := 1; else 0
2796 Wr_Reg rT, TMP ; Regs[rT] := TMP (result)
2797 jmp _end_cycle
2798 ;-----------------------------------------------------------------------------
2799
2800 ;-----------------------------------------------------------------------------
2801 ; ANDI -- Bitwise AND immediate.
2802 ; Bitwise ANDs a register and an immediate value and stores the result
2803 ; in a register
2804 ; Operation: $t = $s & imm; advance_pc(4);
2805 ; Syntax: andi $t, $s, imm
2806 ; Encoding: 0011 00ss ssst tttt iiii iiii iiii iiii
2807 ;-----------------------------------------------------------------------------
2808 align GRAIN, db 0x90
2809 _i_andi:
2810 IType ; Load Imm, rS, rT Fields
2811 mov TMP, R(rS) ; TMP := Regs[rS]
2812 and TMP, Imm ; TMP := TMP & Imm
2813 Wr_Reg rT, TMP ; Regs[rT] := TMP (result)
2814 jmp _end_cycle
2815 ;-----------------------------------------------------------------------------
2816
2817 ;-----------------------------------------------------------------------------
2818 ; ORI -- Bitwise OR immediate.
2819 ; Bitwise OrS a register and an immediate value and stores the result
2820 ; in a register
2821 ; Operation: $t = $s | imm; advance_pc(4);
2822 ; Syntax: ori $t, $s, imm
2823 ; Encoding: 0011 01ss ssst tttt iiii iiii iiii iiii
2824 ;-----------------------------------------------------------------------------
2825 align GRAIN, db 0x90
2826 _i_ori:
2827 IType ; Load Imm, rS, rT Fields
2828 mov TMP, R(rS) ; TMP := Regs[rS]
2829 or TMP, Imm ; TMP := TMP | Imm
2830 Wr_Reg rT, TMP ; Regs[rT] := TMP (result)
2831 jmp _end_cycle
2832 ;-----------------------------------------------------------------------------
2833
2834 ;-----------------------------------------------------------------------------
2835 ; XORI -- Bitwise Exclusive Or immediate.
2836 ; Bitwise XOrS a register and an immediate value and stores the
2837 ; result in a register
2838 ; Operation: $t = $s ^ imm; advance_pc(4);
2839 ; Syntax: xori $t, $s, imm
2840 ; Encoding: 0011 10ss ssst tttt iiii iiii iiii iiii
2841 ;-----------------------------------------------------------------------------
2842 align GRAIN, db 0x90
2843 _i_xori:
2844 IType ; Load Imm, rS, rT Fields
2845 mov TMP, R(rS) ; TMP := Regs[rS]
2846 xor TMP, Imm ; TMP := TMP ^ Imm
2847 Wr_Reg rT, TMP ; Regs[rT] := TMP (result)
2848 jmp _end_cycle
2849 ;-----------------------------------------------------------------------------
2850
2851 ;-----------------------------------------------------------------------------
2852 ; LUI -- Load upper immediate.
2853 ; The immediate value is shifted left 16 bits and stored in the register.
2854 ; The lower 16 bits are zeroes.
2855 ; Operation: $t = (imm << 16); advance_pc(4);
2856 ; Syntax: lui $t, imm
2857 ; Encoding: 0011 11-- ---t tttt iiii iiii iiii iiii
2858 ;-----------------------------------------------------------------------------
2859 align GRAIN, db 0x90
2860 _i_lui:
2861 IType_I_T_Only ; Load Imm and rT Fields
2862 mov TMP, Imm ; TMP := Imm
2863 shl TMP, 16 ; TMP := TMP << 16
2864 Wr_Reg rT, TMP ; Regs[rT] := TMP (result)
2865 jmp _end_cycle
2866 ;-----------------------------------------------------------------------------
2867
2868 ;-----------------------------------------------------------------------------
2869 ; BEQL - Branch on Equal Likely.
2870 ; Compare registers, then do a PC-relative conditional branch;
2871 ; execute the delay slot only if the branch is taken.
2872 ; An 18-bit signed offset (the 16-bit offset field shifted left 2 bits) is
2873 ; added to the address of the instruction following the branch (not the
2874 ; branch itself), in the branch delay slot, to form a PC-relative effective
2875 ; target address. If the contents of rS and rT are equal, branch to the target
2876 ; address after the instruction in the delay slot is executed. If the branch
2877 ; is not taken, the instruction in the delay slot is not executed.
2878 ; Operation: if rS = rT then branch_likely
2879 ; Syntax: beql $s, $t, offset
2880 ; Encoding: 0101 00ss ssst tttt iiii iiii iiii iiii
2881 ;-----------------------------------------------------------------------------
2882 align GRAIN, db 0x90
2883 _i_beql:
2884 IType ; Load Imm, rS, rT Fields
2885 mov TMP, R(rS) ; TMP := Regs[rS]
2886 cmp TMP, R(rT) ; CMP(TMP, Regs[rT])
2887 jne _i_beql_not_taken ; If !(TMP = Regs[rT]) then NotTaken
2888 ; Taken:
2889 SX18_4N Imm ; Sign Extend Imm * 4
2890 mov nPC, PC ; nPC := PC
2891 add nPC, 0x4 ; nPC := nPC + 4
2892 add nPC, Imm ; nPC := nPC + Offset
2893 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2894 jmp _end_cycle
2895 ; Not Taken:
2896 _i_beql_not_taken:
2897 add PC, 0x4 ; PC := PC + 4
2898 jmp _end_cycle
2899 ;-----------------------------------------------------------------------------
2900
2901 ;-----------------------------------------------------------------------------
2902 ; BNEL - Branch on Not Equal Likely.
2903 ; Compare registers, then do a PC-relative conditional branch;
2904 ; execute the delay slot only if the branch is taken.
2905 ; An 18-bit signed offset (the 16-bit offset field shifted left 2 bits) is
2906 ; added to the address of the instruction following the branch (not the
2907 ; branch itself), in the branch delay slot, to form a PC-relative effective
2908 ; target address. If the contents of rS and rT are NOT equal, branch to the
2909 ; target address after the instruction in the delay slot is executed. If the
2910 ; branch is not taken, the instruction in the delay slot is not executed.
2911 ; Operation: if rS != rT then branch_likely
2912 ; Syntax: bnel $s, $t, offset
2913 ; Encoding: 0101 01ss ssst tttt iiii iiii iiii iiii
2914 ;-----------------------------------------------------------------------------
2915 align GRAIN, db 0x90
2916 _i_bnel:
2917 IType ; Load Imm, rS, rT Fields
2918 mov TMP, R(rS) ; TMP := Regs[rS]
2919 cmp TMP, R(rT) ; CMP(TMP, Regs[rT])
2920 je _i_bnel_not_taken ; If !(TMP != Regs[rT]) then NotTaken
2921 ; Taken:
2922 SX18_4N Imm ; Sign Extend Imm * 4
2923 mov nPC, PC ; nPC := PC
2924 add nPC, 0x4 ; nPC := nPC + 4
2925 add nPC, Imm ; nPC := nPC + Offset
2926 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2927 jmp _end_cycle
2928 ; Not Taken:
2929 _i_bnel_not_taken:
2930 add PC, 0x4 ; PC := PC + 4
2931 jmp _end_cycle
2932 ;-----------------------------------------------------------------------------
2933
2934 ;-----------------------------------------------------------------------------
2935 ; BLEZL - Branch on Less Than or Equal to Zero Likely.
2936 ; Test a register, then do a PC-relative conditional branch;
2937 ; execute the delay slot only if the branch is taken.
2938 ; An 18-bit signed offset (the 16-bit offset field shifted left 2 bits) is
2939 ; added to the address of the instruction following the branch (not the branch
2940 ; itself), in the branch delay slot, to form a PC-relative effective target
2941 ; address. If the contents of rS are less than or equal to zero (sign bit is
2942 ; 1 or value is zero), branch to the effective target address after the
2943 ; instruction in the delay slot is executed. If the branch is not taken, the
2944 ; instruction in the delay slot is not executed.
2945 ; Operation: If rS <= 0 then branch_likely
2946 ; Syntax: bltzl $s, offset
2947 ; Encoding: 0101 10ss sss0 0000 iiii iiii iiii iiii
2948 ;-----------------------------------------------------------------------------
2949 align GRAIN, db 0x90
2950 _i_blezl:
2951 IType_S_Only ; load only rS Field just now
2952 cmp R(rS), 0 ; CMP(Regs[rS], 0)
2953 jnle _i_blezl_not_taken ; If !(Regs[rS] <= 0) then NotTaken
2954 ; Taken:
2955 IType_I_Only ; load only Imm Field just now
2956 SX18_4N Imm ; Sign Extend Imm * 4
2957 mov nPC, PC ; nPC := PC
2958 add nPC, 0x4 ; nPC := nPC + 4
2959 add nPC, Imm ; nPC := nPC + Offset
2960 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2961 jmp _end_cycle
2962 ; Not Taken:
2963 _i_blezl_not_taken:
2964 add PC, 0x4 ; PC := PC + 4
2965 jmp _end_cycle
2966 ;-----------------------------------------------------------------------------
2967
2968 ;-----------------------------------------------------------------------------
2969 ; BGTZL - Branch on Greater Than Zero Likely.
2970 ; Test a register, then do a PC-relative conditional branch;
2971 ; execute the delay slot only if the branch is taken.
2972 ; An 18-bit signed offset (the 16-bit offset field shifted left 2 bits) is
2973 ; added to the address of the instruction following the branch (not the branch
2974 ; itself), in the branch delay slot, to form a PC-relative effective target
2975 ; address. If the contents of rS are greater than zero (sign bit is 0 but
2976 ; value not zero), branch to the effective target address after the
2977 ; instruction in the delay slot is executed. If the branch is not taken, the
2978 ; instruction in the delay slot is not executed.
2979 ; Operation: If rS > 0 then branch_likely
2980 ; Syntax: bgtzl $s, offset
2981 ; Encoding: 0101 11ss sss0 0000 iiii iiii iiii iiii
2982 ;-----------------------------------------------------------------------------
2983 align GRAIN, db 0x90
2984 _i_bgtzl:
2985 IType_S_Only ; load only rS Field just now
2986 cmp R(rS), 0 ; CMP(Regs[rS], 0)
2987 jng _i_bgtzl_not_taken ; If !(Regs[rS] > 0) then NotTaken
2988 ; Taken:
2989 IType_I_Only ; load only Imm Field just now
2990 SX18_4N Imm ; Sign Extend Imm * 4
2991 mov nPC, PC ; nPC := PC
2992 add nPC, 0x4 ; nPC := nPC + 4
2993 add nPC, Imm ; nPC := nPC + Offset
2994 Flg_On InDelaySlot ; Set 'Delay Slot' Flag.
2995 jmp _end_cycle
2996 ; Not Taken:
2997 _i_bgtzl_not_taken:
2998 add PC, 0x4 ; PC := PC + 4
2999 jmp _end_cycle
3000 ;-----------------------------------------------------------------------------
3001
3002 ;-----------------------------------------------------------------------------
3003 ; MUL - Multiply Word to Register.
3004 ; The 32-bit word value in rS is multiplied by the 32-bit value in rT,
3005 ; treating both operands as signed values, to produce a 64-bit result.
3006 ; The least significant 32 bits of the product are written to rD.
3007 ; The contents of HI and LO are UNPREDICTABLE after the operation.
3008 ; No arithmetic exception occurs under any circumstances.
3009 ; Syntax: mul $d, $s, $t
3010 ; Encoding: 0111 00ss ssst tttt dddd d000 0000 0010
3011 ;-----------------------------------------------------------------------------
3012 ; TODO: untested
3013 align GRAIN, db 0x90
3014 _i_mul:
3015 RType ; load rD, rS, rT Fields
3016 mov TMP, R(rT) ; TMP := Regs[rT]
3017 imul TMP, R(rS) ; TMP := TMP * Regs[rS] (Bottom 32 bits)
3018 Wr_Reg rD, TMP ; Regs[rD] := Bottom 32 bits of prod
3019 jmp _end_cycle
3020 ;-----------------------------------------------------------------------------
3021
3022 ;-----------------------------------------------------------------------------
3023 ; LB -- Load Byte.
3024 ; A byte is loaded into a register from the specified address.
3025 ; Operation: $t = MEM[$s + offset]; advance_pc(4);
3026 ; Syntax: lb $t, offset($s)
3027 ; Encoding: 1000 00ss ssst tttt iiii iiii iiii iiii
3028 ;-----------------------------------------------------------------------------
3029 align GRAIN, db 0x90
3030 _i_lb:
3031 IType ; Load Imm, rS, rT Fields
3032 SX16 Imm ; Sign-extend the Imm offset
3033 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3034 call _Virt_Read_Byte ; AL := Virt_Read_Byte(EAX)
3035 shl eax, 24 ; Shift left for sign-extension:
3036 sar eax, 24 ; Shift back right, dragging sign bit:
3037 Wr_Reg rT, EAX ; Regs[rT] := EAX
3038 jmp _end_cycle
3039 ;-----------------------------------------------------------------------------
3040
3041 ;-----------------------------------------------------------------------------
3042 ; LH - Load Halfword.
3043 ; Load a halfword from memory as a signed value.
3044 ; The contents of the 16-bit halfword at the memory location specified by the
3045 ; aligned effective address are fetched, sign-extended, and placed in rT.
3046 ; The 16-bit signed offset is added to the contents of rS to form the
3047 ; effective address. The effective address must be naturally-aligned.
3048 ; If the least-significant bit of the address is non-zero, an Address
3049 ; Error exception occurs
3050 ; Operation: $t = MEM[$s + offset]; advance_pc(4);
3051 ; Syntax: lh $t, offset($s)
3052 ; Encoding: 1000 01ss ssst tttt iiii iiii iiii iiii
3053 ;-----------------------------------------------------------------------------
3054 ; NOTE: LHU is exactly same thing as LH, but without sign-extend.
3055 align GRAIN, db 0x90
3056 _i_lh:
3057 IType ; Load Imm, rS, rT Fields
3058 SX16 Imm ; Sign-extend the Imm offset
3059 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3060 ;; rS (ecx) is not needed any more, can be reused
3061 bt Imm, 0 ; Get low bit of vAddr
3062 jnc _i_lh_aligned_ok ; If zero, vAddr was properly aligned;
3063 SetEXC EXC_AdEL ; If vAddr was NOT properly aligned:
3064 jmp _Handle_Exception ; Go straight to exception handler.
3065 _i_lh_aligned_ok: ; Load is to proceed normally:
3066 mov ecx, Imm ; Save vAddr to ECX
3067 xor TMP, TMP ; Clear TMP, where we will put the HW
3068 %ifdef LITTLE_ENDIAN
3069 ;; Read the low byte of the HW first:
3070 call _Virt_Read_Byte ; EAX := Virt_Read_Byte(vAddr)
3071 mov TMP, eax ; TMP := eax (save the low byte)
3072 ;; Now read the high byte:
3073 mov eax, ecx ; Restore the original saved vAddr
3074 or eax, 1 ; Will read vAddr + 1
3075 call _Virt_Read_Byte ; EAX := Virt_Read_Byte(vAddr + 1)
3076 %else
3077 or Imm, 1 ; First, read vAddr + 1 :
3078 call _Virt_Read_Byte ; EAX := Virt_Read_Byte(vAddr + 1)
3079 mov TMP, eax ; TMP := eax (save low byte)
3080 mov eax, ecx ; Restore the original saved vAddr
3081 call _Virt_Read_Byte ; EAX := Virt_Read_Byte(vAddr)
3082 %endif
3083 shl eax, 8 ; eax := eax << 8
3084 or eax, TMP ; eax := eax | TMP (high | low)
3085 shl eax, 16 ; left shift eax to put the HW on top
3086 sar eax, 16 ; right shift it back, to sign-extend.
3087 Wr_Reg rT, eax ; Regs[rT] := EAX (write back result)
3088 jmp _end_cycle
3089 ;-----------------------------------------------------------------------------
3090
3091 ;-----------------------------------------------------------------------------
3092 ; LWL - Load Word Left.
3093 ; Load the most-significant part of a word as a signed value from an unaligned
3094 ; memory address.
3095 ; Operation: $t = $t MERGE MEM[$s + offset]; advance_pc(4);
3096 ; Syntax: lwl $t, offset($s)
3097 ; Encoding: 1000 10ss ssst tttt iiii iiii iiii iiii
3098 ;-----------------------------------------------------------------------------
3099 align GRAIN, db 0x90
3100 _i_lwl:
3101 IType ; Load Imm, rS, rT Fields
3102 SX16 Imm ; Sign-extend the Imm offset
3103 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3104 ;; rS (ecx) is not needed any more, can be reused
3105 mov TMP, R(rT) ; TMP := Regs[rT] (old reg value)
3106 mov AUX, Imm ; Save the original unaligned address
3107 and Imm, ~(0x3) ; Clear bottom two bits of address
3108 call _Virt_Read_Word ; EAX := Virt_Read_Word(EAX (aligned))
3109 ;; Proceed with write. EAX : old word, TMP : new word, ebx : still rT
3110 mov ecx, AUX ; ecx := original unaligned address
3111 and ecx, 0x3 ; keep only bottom two bits of it
3112 shl ecx, 3 ; ecx := ecx (8 * (addr[0..2]))
3113 shl eax, cl ; left shift eax (orig word) by above
3114 xor ecx, 24 ; ecx := 24 - ecx
3115 mov AUX, 0xFFFFFF ; AUX := 0xFFFFFF
3116 shr AUX, cl ; AUX := AUX >> cl
3117 and TMP, AUX ; TMP := TMP & AUX
3118 or TMP, eax ; TMP := TMP | eax (the writeback value)
3119 Wr_Reg rT, TMP ; Regs[rT] := TMP (the writeback value)
3120 jmp _end_cycle
3121 ;-----------------------------------------------------------------------------
3122
3123 ;-----------------------------------------------------------------------------
3124 ; LW -- Load Word.
3125 ; The contents of the 32-bit word at the memory location specified by the
3126 ; aligned effective address are fetched, signextended to the register length
3127 ; if necessary, and placed in register rT. The 16-bit signed offset is added
3128 ; to the contents of the base to form the effective address.
3129 ; Operation: $t = MEM[$s + offset]; advance_pc(4);
3130 ; Syntax: lw $t, offset($s)
3131 ; Encoding: 1000 11ss ssst tttt iiii iiii iiii iiii
3132 ;-----------------------------------------------------------------------------
3133 align GRAIN, db 0x90
3134 _i_lw:
3135 IType ; Load Imm, rS, rT Fields
3136 SX16 Imm ; Sign-extend the Imm offset
3137 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3138 call _Virt_Read_Word ; EAX := Virt_Read_Word(EAX)
3139 Wr_Reg rT, EAX ; Regs[rT] := EAX
3140 jmp _end_cycle
3141 ;-----------------------------------------------------------------------------
3142
3143 ;-----------------------------------------------------------------------------
3144 ; LBU - Load Byte Unsigned.
3145 ; Load a byte from memory as an unsigned value.
3146 ; The contents of the 8-bit byte at the memory location specified by the
3147 ; effective address are fetched, zero-extended, and placed in rT.
3148 ; The 16-bit signed offset is added to the contents of rS to form the
3149 ; effective address.
3150 ; Operation: $t = MEM[$s + offset]; advance_pc(4);
3151 ; Syntax: lbu $t, offset($s)
3152 ; Encoding: 1001 00ss ssst tttt iiii iiii iiii iiii
3153 ;-----------------------------------------------------------------------------
3154 align GRAIN, db 0x90
3155 _i_lbu:
3156 IType ; Load Imm, rS, rT Fields
3157 SX16 Imm ; Sign-extend the Imm offset
3158 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3159 call _Virt_Read_Byte ; AL := Virt_Read_Byte(EAX)
3160 Wr_Reg rT, EAX ; Regs[rT] := EAX
3161 jmp _end_cycle
3162 ;-----------------------------------------------------------------------------
3163
3164 ;-----------------------------------------------------------------------------
3165 ; LHU - Load Halfword Unsigned.
3166 ; Load a halfword from memory as an unsigned value.
3167 ; The contents of the 16-bit halfword at the memory location specified by the
3168 ; aligned effective address are fetched, zero-extended, and placed in reg rT.
3169 ; The 16-bit signed offset is added to the contents of register rS to form the
3170 ; effective address. The effective address must be naturally-aligned.
3171 ; If the least-significant bit of the address is non-zero,
3172 ; an Address Error exception occurs.
3173 ; Operation: $t = MEM[$s + offset]; advance_pc(4);
3174 ; Syntax: lhu $t, offset($s)
3175 ; Encoding: 1001 01ss ssst tttt iiii iiii iiii iiii
3176 ;-----------------------------------------------------------------------------
3177 ; NOTE: exactly same thing as LH, but WITHOUT sign-extend.
3178 align GRAIN, db 0x90
3179 _i_lhu:
3180 IType ; Load Imm, rS, rT Fields
3181 SX16 Imm ; Sign-extend the Imm offset
3182 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3183 ;; rS (ecx) is not needed any more, can be reused
3184 bt Imm, 0 ; Get low bit of vAddr
3185 jnc _i_lhu_aligned_ok ; If zero, vAddr was properly aligned;
3186 SetEXC EXC_AdEL ; If vAddr was NOT properly aligned:
3187 jmp _Handle_Exception ; Go straight to exception handler.
3188 _i_lhu_aligned_ok: ; Load is to proceed normally:
3189 mov ecx, Imm ; Save vAddr to ECX
3190 xor TMP, TMP ; Clear TMP, where we will put the HW
3191 %ifdef LITTLE_ENDIAN
3192 ;; Read the low byte of the HW first:
3193 call _Virt_Read_Byte ; EAX := Virt_Read_Byte(vAddr + 1)
3194 mov TMP, eax ; TMP := eax (save the low byte)
3195 ;; Now read the high byte:
3196 mov eax, ecx ; Restore the original saved vAddr
3197 or eax, 1 ; Will read vAddr + 1
3198 call _Virt_Read_Byte ; EAX := Virt_Read_Byte(vAddr + 1)
3199 %else
3200 or Imm, 1 ; First, read vAddr + 1 :
3201 call _Virt_Read_Byte ; EAX := Virt_Read_Byte(vAddr + 1)
3202 mov TMP, eax ; TMP := eax (save low byte)
3203 mov eax, ecx ; Restore the original saved vAddr
3204 call _Virt_Read_Byte ; EAX := Virt_Read_Byte(vAddr)
3205 %endif
3206 shl eax, 8 ; eax := eax << 8
3207 or eax, TMP ; eax := eax | TMP (high | low)
3208 Wr_Reg rT, eax ; Regs[rT] := EAX (write back result)
3209 jmp _end_cycle
3210 ;-----------------------------------------------------------------------------
3211
3212 ;-----------------------------------------------------------------------------
3213 ; LWL - Load Word Right.
3214 ; Load the least-significant part of a word from an unaligned memory address
3215 ; as a signed value. The 16-bit signed offset is added to the contents of rS
3216 ; to form an effective address (EffAddr). EffAddr is the address of the
3217 ; least-significant of 4 consecutive bytes forming a word (W) in memory
3218 ; starting at an arbitrary byte boundary. A part of W, the least-significant
3219 ; 1 to 4 bytes, is in the aligned word containing EffAddr. This part of W is
3220 ; loaded into the least-significant (right) part of the word in register rT.
3221 ; The remaining most-significant part of the word in register rT is unchanged.
3222 ; Executing both LWR and LWL, in either order, delivers a sign-extended word
3223 ; value in the destination register.
3224 ; Operation: $t = $t MERGE MEM[$s + offset]; advance_pc(4);
3225 ; Syntax: lwr $t, offset($s)
3226 ; Encoding: 1001 10ss ssst tttt iiii iiii iiii iiii
3227 ;-----------------------------------------------------------------------------
3228 align GRAIN, db 0x90
3229 _i_lwr:
3230 IType ; Load Imm, rS, rT Fields
3231 SX16 Imm ; Sign-extend the Imm offset
3232 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3233 ;; rS (ecx) is not needed any more, can be reused
3234 mov TMP, R(rT) ; TMP := Regs[rT] (value to write)
3235 mov AUX, Imm ; Save the original unaligned address
3236 and Imm, ~(0x3) ; Clear bottom two bits of address
3237 call _Virt_Read_Word ; EAX := Virt_Read_Word(EAX (aligned))
3238 ;; Proceed with write. EAX : old word, TMP : new word, ebx : still rT
3239 mov ecx, AUX ; ecx := original unaligned address
3240 and ecx, 0x3 ; keep only bottom two bits of it
3241 shl ecx, 3 ; ecx := ecx (8 * (addr[0..2]))
3242 mov AUX, 0xFFFFFF00 ; AUX := 0xFFFFFF00
3243 shl AUX, cl ; AUX := AUX << cl
3244 and TMP, AUX ; TMP := TMP & AUX
3245 xor ecx, 24 ; ecx := 24 - ecx
3246 shr eax, cl ; right shift eax (orig word) by above
3247 or TMP, eax ; TMP := TMP | eax (the writeback value)
3248 Wr_Reg rT, TMP ; Regs[rT] := TMP (the writeback value)
3249 jmp _end_cycle
3250 ;-----------------------------------------------------------------------------
3251
3252 ;-----------------------------------------------------------------------------
3253 ; SB -- Store Byte.
3254 ; The least significant byte of $t is stored at the specified address.
3255 ; Operation: MEM[$s + offset] = (0xff & $t); advance_pc(4);
3256 ; Syntax: sb $t, offset($s)
3257 ; Encoding: 1010 00ss ssst tttt iiii iiii iiii iiii
3258 ;-----------------------------------------------------------------------------
3259 align GRAIN, db 0x90
3260 _i_sb:
3261 IType ; Load Imm, rS, rT Fields
3262 SX16 Imm ; Sign-extend the Imm offset
3263 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3264 mov TMP, R(rT) ; TMP (EDX) := Regs[rT]
3265 and TMP, 0xFF ; Keep only low byte of TMP
3266 call _Virt_Write_Byte ; Virt_Write_Byte(EAX, DL)
3267 jmp _end_cycle
3268 ;-----------------------------------------------------------------------------
3269
3270 ;-----------------------------------------------------------------------------
3271 ; SH - Store Halfword.
3272 ; Store a halfword to memory. The least-significant 16-bit halfword of
3273 ; register rT is stored in memory at the location specified by the aligned
3274 ; effective address. The 16-bit signed offset is added to the contents of rS
3275 ; to form the effective address.
3276 ; The effective address must be naturally-aligned. If the least-significant
3277 ; bit of the address is non-zero, an Address Error exception occurs.
3278 ; Operation: MEM[$s + offset] = $t; advance_pc(4);
3279 ; Syntax: sh $t, offset($s)
3280 ; Encoding: 1010 01ss ssst tttt iiii iiii iiii iiii
3281 ;-----------------------------------------------------------------------------
3282 align GRAIN, db 0x90
3283 _i_sh:
3284 IType ; Load Imm, rS, rT Fields
3285 SX16 Imm ; Sign-extend the Imm offset
3286 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3287 bt Imm, 0 ; Get low bit of vAddr
3288 jnc _i_sh_aligned_ok ; If zero, vAddr was properly aligned;
3289 SetEXC EXC_AdES ; If vAddr was NOT properly aligned:
3290 jmp _Handle_Exception ; Go straight to exception handler.
3291 _i_sh_aligned_ok:
3292 mov AUX, Imm ; Save Imm (vAddr) to AUX
3293 ;; rS (ecx) is not needed any more, can be reused
3294 mov ecx, R(rT) ; ecx := Regs[rT] (HW to be written)
3295 mov TMP, ecx ; TMP := ecx
3296 %ifdef LITTLE_ENDIAN
3297 and TMP, 0xFF ; isolate low byte
3298 call _Virt_Write_Byte ; Virt_Write_Byte(vAddr, DL)
3299 mov TMP, ecx ; TMP := the whole HW again
3300 and TMP, 0xFF00 ; isolate high byte
3301 shr TMP, 8 ; TMP := TMP >> 8 (get high byte)
3302 %else ;; Big-Endian
3303 shr TMP, 8 ; TMP := TMP >> 8 (get high byte)
3304 call _Virt_Write_Byte ; Virt_Write_Byte(vAddr, DL)
3305 mov TMP, ecx ; TMP := ecx again, now for low byte
3306 and TMP, 0xFF ; isolate low byte
3307 %endif
3308 mov eax, AUX ; restore vAddr from AUX
3309 or eax, 1 ; set bottom bit, for vAddr + 1
3310 call _Virt_Write_Byte ; Virt_Write_Byte(vAddr + 1, DL)
3311 jmp _end_cycle
3312 ;-----------------------------------------------------------------------------
3313
3314 ;-----------------------------------------------------------------------------
3315 ; SWL - Store Word Left.
3316 ; Store the most-significant part of a word to an unaligned memory address.
3317 ; Operation: MEM[$s + offset] = $t; advance_pc(4);
3318 ; Syntax: swl $t, offset($s)
3319 ; Encoding: 1010 10ss ssst tttt iiii iiii iiii iiii
3320 ;-----------------------------------------------------------------------------
3321 align GRAIN, db 0x90
3322 _i_swl:
3323 IType ; Load Imm, rS, rT Fields
3324 SX16 Imm ; Sign-extend the Imm offset
3325 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3326 ;; rS (ecx) is not needed any more, can be reused
3327 mov TMP, R(rT) ; TMP := Regs[rT] (old reg value)
3328 ;; rT (ebx) is not needed any more, can be reused
3329 mov AUX, Imm ; Save the original unaligned address
3330 and Imm, ~(0x3) ; Clear bottom two bits of address
3331 mov ebx, Imm ; Save the aligned address for writeback
3332 call _Virt_Read_Word ; EAX := Virt_Read_Word(EAX (aligned))
3333 ;; Proceed with write. EAX : old word, TMP : new word, ebx : WB addr.
3334 mov ecx, AUX ; ecx := original unaligned address
3335 and ecx, 0x3 ; keep only bottom two bits
3336 shl ecx, 3 ; ecx := ecx (8 * (addr[0..2]))
3337 shr TMP, cl ; right shift TMP by above
3338 xor ecx, 24 ; ecx := 24 - ecx
3339 mov AUX, 0xFFFFFF00 ; AUX := 0xFFFFFF00
3340 shl AUX, cl ; AUX := AUX << cl
3341 and eax, AUX ; eax := eax & AUX
3342 or TMP, eax ; TMP := TMP | eax (the writeback value)
3343 mov eax, ebx ; restore aligned address for writeback
3344 call _Virt_Write_Word ; Virt_Write_Word(EAX, TMP)
3345 jmp _end_cycle
3346 ;-----------------------------------------------------------------------------
3347
3348 ;-----------------------------------------------------------------------------
3349 ; SW -- Store Word.
3350 ; The contents of $t is stored at the specified address.
3351 ; The effective address must be naturally-aligned.
3352 ; If either of the 2 least-significant bits of the address is non-zero,
3353 ; an Address Error exception occurs.
3354 ; Operation: MEM[$s + offset] = $t; advance_pc(4);
3355 ; Syntax: sw $t, offset($s)
3356 ; Encoding: 1010 11ss ssst tttt iiii iiii iiii iiii
3357 ;-----------------------------------------------------------------------------
3358 align GRAIN, db 0x90
3359 _i_sw:
3360 IType ; Load Imm, rS, rT Fields
3361 SX16 Imm ; Sign-extend the Imm offset
3362 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3363 mov TMP, R(rT) ; TMP := Regs[rT]
3364 call _Virt_Write_Word ; Virt_Write_Word(EAX, TMP)
3365 jmp _end_cycle
3366 ;-----------------------------------------------------------------------------
3367
3368 ;-----------------------------------------------------------------------------
3369 ; SWR - Store Word Right.
3370 ; Store the least-significant part of a word to an unaligned memory address.
3371 ; Operation: MEM[$s + offset] = $t; advance_pc(4);
3372 ; Syntax: swr $t, offset($s)
3373 ; Encoding: 1011 10ss ssst tttt iiii iiii iiii iiii
3374 ;-----------------------------------------------------------------------------
3375 align GRAIN, db 0x90
3376 _i_swr:
3377 IType ; Load Imm, rS, rT Fields
3378 SX16 Imm ; Sign-extend the Imm offset
3379 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3380 ;; rS (ecx) is not needed any more, can be reused
3381 mov TMP, R(rT) ; TMP := Regs[rT] (value to write)
3382 ;; rT (ebx) is not needed any more, can be reused
3383 mov AUX, Imm ; Save the original unaligned address
3384 and Imm, ~(0x3) ; Clear bottom two bits of address
3385 mov ebx, Imm ; Save the aligned address for writeback
3386 call _Virt_Read_Word ; EAX := Virt_Read_Word(EAX (aligned))
3387 ;; Proceed with write. EAX : old word, TMP : new word, ebx : WB addr.
3388 mov ecx, AUX ; ecx := original unaligned address
3389 and ecx, 0x3 ; keep only bottom two bits
3390 shl ecx, 3 ; ecx := ecx * 8
3391 mov AUX, 0xFFFFFF ; AUX := 0xFFFFFF
3392 shr AUX, cl ; AUX := AUX >> cl
3393 and eax, AUX ; eax := eax & AUX
3394 xor ecx, 24 ; ecx := 24 - ecx (24 - 8 * (addr[0..2]))
3395 shl TMP, cl ; left shift TMP (value to write) by above
3396 or TMP, eax ; TMP := TMP | eax (the writeback value)
3397 mov eax, ebx ; restore aligned address for writeback
3398 call _Virt_Write_Word ; Virt_Write_Word(EAX, TMP)
3399 jmp _end_cycle
3400 ;-----------------------------------------------------------------------------
3401
3402 ;-----------------------------------------------------------------------------
3403 ; CACHE.
3404 ; Operation: This is a NOP in this emulator.
3405 ; Syntax: cache $t, offset($s)
3406 ; Encoding: 1011 11ss ssst tttt iiii iiii iiii iiii
3407 ; PRIVILEGED (permitted in Kernel Mode only.)
3408 ;-----------------------------------------------------------------------------
3409 align GRAIN, db 0x90
3410 _i_cache:
3411 ; no fields
3412 PRIVILEGED ; Permitted in Kernel Mode only.
3413 jmp _end_cycle
3414 ;-----------------------------------------------------------------------------
3415
3416 ;-----------------------------------------------------------------------------
3417 ; LL - Load Linked Word.
3418 ; Load a word from memory for an atomic read-modify-write.
3419 ; The contents of the 32-bit word at the memory location specified by the
3420 ; aligned effective address are fetched and written into register rT.
3421 ; The 16-bit signed offset is added to the contents of rS to form
3422 ; an effective address.
3423 ; Operation: $t = MEM[$s + offset]; llbit = 1; advance_pc(4);
3424 ; Syntax: ll $t, offset($s)
3425 ; Encoding: 1100 00ss ssst tttt iiii iiii iiii iiii
3426 ;-----------------------------------------------------------------------------
3427 align GRAIN, db 0x90
3428 _i_ll:
3429 IType ; Load Imm, rS, rT Fields
3430 SX16 Imm ; Sign-extend the Imm offset
3431 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3432 call _Virt_Read_Word ; EAX := Virt_Read_Word(EAX)
3433 Wr_Reg rT, EAX ; Regs[rT] := EAX
3434 Flg_On LL_Bit ; Set the LL_Bit Flag
3435 jmp _end_cycle
3436 ;-----------------------------------------------------------------------------
3437
3438 ;-----------------------------------------------------------------------------
3439 ; PREF - Prefetch.
3440 ; Operation: This is a NOP in this emulator.
3441 ; Syntax: pref $t, offset($s)
3442 ; Encoding: 1100 11ss ssst tttt iiii iiii iiii iiii
3443 ;-----------------------------------------------------------------------------
3444 align GRAIN, db 0x90
3445 _i_pref:
3446 ; no fields
3447 jmp _end_cycle
3448 ;-----------------------------------------------------------------------------
3449
3450 ;-----------------------------------------------------------------------------
3451 ; SC - Store Conditional Word.
3452 ; Store a word to memory to complete an atomic read-modify-write.
3453 ; The 32-bit word in rT is conditionally stored in memory at the location
3454 ; specified by the aligned effective address.
3455 ; The 16-bit signed offset is added to the contents of rS to form an
3456 ; effective address
3457 ; Operation: if llbit == 1 then: MEM[$s + offset] = $t; rt = 1; advance_pc(4);
3458 ; else: rt = 0; advance_pc(4);
3459 ; Syntax: sc $t, offset($s)
3460 ; Encoding: 1110 00ss ssst tttt iiii iiii iiii iiii
3461 ;-----------------------------------------------------------------------------
3462 align GRAIN, db 0x90
3463 _i_sc:
3464 IType ; Load Imm, rS, rT Fields
3465 Flg_Get LL_Bit ; CF := LL_Bit
3466 jnc _i_sc_not_taken ; If LL_Bit = 0, then do not store; else:
3467 SX16 Imm ; Sign-extend the Imm offset
3468 add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr)
3469 mov TMP, R(rT) ; TMP := Regs[rT]
3470 call _Virt_Write_Word ; Virt_Write_Word(EAX, TMP)
3471 mov R(rT), 1 ; Regs[rT] := 1 ('yes, stored word')
3472 jmp _i_sc_done ; Done.
3473 _i_sc_not_taken:
3474 mov R(rT), 0 ; Regs[rT] := 0 ('no, did not store')
3475 _i_sc_done:
3476 jmp _end_cycle
3477 ;-----------------------------------------------------------------------------