;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; This file is part of 'M', a MIPS system emulator. ;; ;; ;; ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;; ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;; ;; ;; ;; You do not have, nor can you ever acquire the right to use, copy or ;; ;; distribute this software ; Should you use this software for any purpose, ;; ;; or copy and distribute it to anyone or in any manner, you are breaking ;; ;; the laws of whatever soi-disant jurisdiction, and you promise to ;; ;; continue doing so for the indefinite future. In any case, please ;; ;; always : read and understand any software ; verify any PGP signatures ;; ;; that you use - for any purpose. ;; ;; ;; ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; TODO: 1) Trap for ADDI (gcc 4.8.1 doesn't appear to use, but it exists...) ;; 2) Tests!!! ;------------------------ ; I-Type Instructions : | ;------------------------ ;----------------------------------------------------------------------------- section .rodata align GRAIN, db 0x90 _I_Table: A32 _i_000000 ; 0x00 : All R-Type Instructions A32 _i_000001 ; 0x01 : bltz, bgez, bltzl, bgezl, bltzal, bgezal A32 _i_j ; 0x02 : j (000010??????????????????????????) A32 _i_jal ; 0x03 : jal (000011??????????????????????????) A32 _i_beq ; 0x04 : beq (000100??????????????????????????) A32 _i_bne ; 0x05 : bne (000101??????????????????????????) A32 _i_blez ; 0x06 : blez (000110??????????????????????????) A32 _i_bgtz ; 0x07 : bgtz (000111??????????????????????????) A32 _i_addi ; 0x08 : addi (001000??????????????????????????) A32 _i_addiu ; 0x09 : addiu (001001??????????????????????????) A32 _i_slti ; 0x0a : slti (001010??????????????????????????) A32 _i_sltiu ; 0x0b : sltiu (001011??????????????????????????) A32 _i_andi ; 0x0c : andi (001100??????????????????????????) A32 _i_ori ; 0x0d : ori (001101??????????????????????????) A32 _i_xori ; 0x0e : xori (001110??????????????????????????) A32 _i_lui ; 0x0f : lui (001111??????????????????????????) A32 _i_010000 ; 0x10 : mfc0, mtc0, tlbwi, tlbwr, tlbp, eret, wait A32 _bad ; 0x11 : UNDEFINED A32 _bad ; 0x12 : UNDEFINED A32 _bad ; 0x13 : UNDEFINED A32 _i_beql ; 0x14 : beql (010100??????????????????????????) A32 _i_bnel ; 0x15 : bnel (010101??????????????????????????) A32 _i_blezl ; 0x16 : blezl (010110??????????????????????????) A32 _i_bgtzl ; 0x17 : bgtzl (010111?????00000????????????????) A32 _bad ; 0x18 : UNDEFINED A32 _bad ; 0x19 : UNDEFINED A32 _bad ; 0x1a : UNDEFINED A32 _bad ; 0x1b : UNDEFINED A32 _i_mul ; 0x1c : mul (011100???????????????00000000010) A32 _bad ; 0x1d : UNDEFINED A32 _bad ; 0x1e : UNDEFINED A32 _bad ; 0x1f : UNDEFINED A32 _i_lb ; 0x20 : lb (100000??????????????????????????) A32 _i_lh ; 0x21 : lh (100001??????????????????????????) A32 _i_lwl ; 0x22 : lwl (100010??????????????????????????) A32 _i_lw ; 0x23 : lw (100011??????????????????????????) A32 _i_lbu ; 0x24 : lbu (100100??????????????????????????) A32 _i_lhu ; 0x25 : lhu (100101??????????????????????????) A32 _i_lwr ; 0x26 : lwr (100110??????????????????????????) A32 _bad ; 0x27 : UNDEFINED A32 _i_sb ; 0x28 : sb (101000??????????????????????????) A32 _i_sh ; 0x29 : sh (101001??????????????????????????) A32 _i_swl ; 0x2a : swl (101010??????????????????????????) A32 _i_sw ; 0x2b : sw (101011??????????????????????????) A32 _bad ; 0x2c : UNDEFINED A32 _bad ; 0x2d : UNDEFINED A32 _i_swr ; 0x2e : swr (101110??????????????????????????) A32 _i_cache ; 0x2f : cache (101111??????????????????????????) A32 _i_ll ; 0x30 : ll (110000??????????????????????????) A32 _bad ; 0x31 : UNDEFINED A32 _bad ; 0x32 : UNDEFINED A32 _i_pref ; 0x33 : pref (110011??????????????????????????) A32 _bad ; 0x34 : UNDEFINED A32 _bad ; 0x35 : UNDEFINED A32 _bad ; 0x36 : UNDEFINED A32 _bad ; 0x37 : UNDEFINED A32 _i_sc ; 0x38 : sc (111000??????????????????????????) A32 _bad ; 0x39 : UNDEFINED A32 _bad ; 0x3a : UNDEFINED A32 _bad ; 0x3b : UNDEFINED A32 _bad ; 0x3c : UNDEFINED A32 _bad ; 0x3d : UNDEFINED A32 _bad ; 0x3e : UNDEFINED A32 _bad ; 0x3f : UNDEFINED ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _MFC0_Table: A32 _mfc0_r00 ; 0x00 A32 _mfc0_r01 ; 0x01 A32 _mfc0_r02 ; 0x02 A32 _mfc0_r03 ; 0x03 A32 _mfc0_r04 ; 0x04 A32 _mfc0_r05 ; 0x05 A32 _mfc0_r06 ; 0x06 A32 _mfc0_r07 ; 0x07 A32 _mfc0_r08 ; 0x08 A32 _mfc0_r09 ; 0x09 A32 _mfc0_r10 ; 0x0a A32 _mfc0_r11 ; 0x0b A32 _mfc0_r12 ; 0x0c A32 _mfc0_r13 ; 0x0d A32 _mfc0_r14 ; 0x0e A32 _mfc0_r15 ; 0x0f A32 _mfc0_r16 ; 0x10 A32 _mfc0_r17 ; 0x11 A32 _mfc0_r18 ; 0x12 A32 _mfc0_r19 ; 0x13 A32 _mfc0_r20 ; 0x14 A32 _mfc0_r21 ; 0x15 A32 _mfc0_r22 ; 0x16 A32 _mfc0_r23 ; 0x17 A32 _mfc0_r24 ; 0x18 A32 _mfc0_r25 ; 0x19 A32 _mfc0_r26 ; 0x1a A32 _mfc0_r27 ; 0x1b A32 _mfc0_r28 ; 0x1c A32 _mfc0_r29 ; 0x1d A32 _mfc0_r30 ; 0x1e A32 _mfc0_r31 ; 0x1f ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _MTC0_Table: A32 _mtc0_r00 ; 0x00 A32 _mtc0_r01 ; 0x01 A32 _mtc0_r02 ; 0x02 A32 _mtc0_r03 ; 0x03 A32 _mtc0_r04 ; 0x04 A32 _mtc0_r05 ; 0x05 A32 _mtc0_r06 ; 0x06 A32 _mtc0_r07 ; 0x07 A32 _mtc0_r08 ; 0x08 A32 _mtc0_r09 ; 0x09 A32 _mtc0_r10 ; 0x0a A32 _mtc0_r11 ; 0x0b A32 _mtc0_r12 ; 0x0c A32 _mtc0_r13 ; 0x0d A32 _mtc0_r14 ; 0x0e A32 _mtc0_r15 ; 0x0f A32 _mtc0_r16 ; 0x10 A32 _mtc0_r17 ; 0x11 A32 _mtc0_r18 ; 0x12 A32 _mtc0_r19 ; 0x13 A32 _mtc0_r20 ; 0x14 A32 _mtc0_r21 ; 0x15 A32 _mtc0_r22 ; 0x16 A32 _mtc0_r23 ; 0x17 A32 _mtc0_r24 ; 0x18 A32 _mtc0_r25 ; 0x19 A32 _mtc0_r26 ; 0x1a A32 _mtc0_r27 ; 0x1b A32 _mtc0_r28 ; 0x1c A32 _mtc0_r29 ; 0x1d A32 _mtc0_r30 ; 0x1e A32 _mtc0_r31 ; 0x1f ;----------------------------------------------------------------------------- section .text ;------------------------ ; Invalid Instruction : | ;------------------------ align GRAIN, db 0x90 _bad: SetEXC EXC_RI ; Set the EXC_RI Exception jmp _Handle_Exception ; Go straight to exception handler. ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; Eat 000000?????????????????????????? (R-Type) Instructions: ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_000000: mov eax, r_I ; Get the original instruction : and eax, 0x3F ; Get funct field, (lower 6 bits) ; JTABLE eax, _R_Table ; Dispatch on funct-field via R-Table. ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; Eat 000001?????QQQQQ???????????????? Branch Instructions : ; i.e. bltz, bgez, bltzl, bgezl, bltzal, bgezal ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_000001: mov eax, r_I ; Get the original instruction : shr eax, 16 ; Get the 5-bit field QQQQQ and eax, 0x1F ; which distinguishes these; JTABLE eax, _B_Table ; Dispatch via B-Table. ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; Eat 010000?????????????????????????? Misc. Instructions : ; mfc0, mtc0, tlbwi, tlbwr, tlbp, eret, wait ; PRIVILEGED (permitted in Kernel Mode only.) ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_010000: PRIVILEGED ; Permitted in Kernel Mode only. mov eax, r_I ; Get the original instruction : shr eax, 5 ; Get the top 27 bits cmp eax, 0x2100000 ; Equal 010000100000000000000000000..? je _tlbwi_tlbwr_tlbp_eret ; 010000100000000000000000000QQQQQ ;; At this point, we have either mfc0, mtc0, wait, or a bad instr: shr eax, 16 ; We already shifted by 5, so now 21: cmp eax, 0x200 ; ... are they equal to 0b01000000000 ? je _m_mfc0 ; mfc0 (01000000000?????????????????????) cmp eax, 0x204 ; ... are they equal to 0b01000000100 ? je _m_mtc0 ; mtc0 (01000000100?????????????????????) ;; Now determine if it is 'wait' (0100001???????????????????100000) : mov eax, r_I ; Get the original instruction : and eax, 0xFE00003F ; Get top 7 bits and bottom 6 bits only cmp eax, 0x42000020 ; Top must be 0b0100001, bottom 0b100000 je _m_wait ; wait (0100001???????????????????100000) ;; Now, if it wasn't the 'wait' instruction, we must then have a turd: jmp _bad ; If we're here : undefined inst. ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; Eat 010000100000000000000000000QQQQQ Instructions (via _i_010000) : ; tlbwi, tlbwr, tlbp, eret ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _tlbwi_tlbwr_tlbp_eret: mov eax, r_I ; Get the original instruction : and eax, 0x1F ; Get the the 5-bit field QQQQQ from it JTABLE eax, _M_Table ; Dispatch via M-Table. ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; J -- Jump. ; Jumps to the calculated address. ; Operation: PC = nPC; nPC = (PC & 0xF0000000) | (target << 2); ; Syntax: j target ; Encoding: 0000 10ii iiii iiii iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_j: JType ; load J Field (ii..iii << 2) mov nPC, PC ; nPC := PC and nPC, 0xF0000000 ; keep only top 4 bits of nPC, zero rest or nPC, JTarg ; nPC := nPC | ( target << 2 ) Flg_On InDelaySlot ; Set 'Delay Slot' Flag. jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; JAL -- Jump and link. ; Jumps to the calculated address and stores the return address in $31. ; Operation: $31 = PC + 8 (or nPC + 4); ; PC = nPC; ; nPC = (PC & 0xF0000000) | (target << 2); ; Syntax: jal target ; Encoding: 0000 11ii iiii iiii iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_jal: JType ; load J Field (ii..iii << 2) mov TMP, PC ; TMP := PC add TMP, 0x8 ; TMP := TMP + 8 mov R(31), TMP ; Regs[31] := TMP sub TMP, 0x8 ; TMP := TMP - 8 and TMP, 0xF0000000 ; keep only top 4 bits of TMP, zero rest or TMP, JTarg ; TMP := TMP | ( target << 2 ) mov nPC, TMP ; nPC := TMP Flg_On InDelaySlot ; Set 'Delay Slot' Flag. jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; BEQ -- Branch on equal. ; Branches if the two registers are equal. ; Operation: if $s == $t advance_pc(offset << 2)); ; else advance_pc(4); ; Syntax: beq $s, $t, offset ; Encoding: 0001 00ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_beq: IType ; Load Imm, rS, rT Fields mov nPC, PC ; nPC := PC add nPC, 0x4 ; nPC := nPC + 4 SX18_4N Imm ; Sign Extend Imm * 4 mov TMP, R(rS) ; TMP := Regs[rS] cmp TMP, R(rT) ; CMP(TMP, Regs[rT]) mov TMP, 0x4 ; TMP := 4 cmove TMP, Imm ; If Regs[rS] = Regs[rT], TMP := Imm add nPC, TMP ; nPC := nPC + TMP Flg_On InDelaySlot ; Set 'Delay Slot' Flag. jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; BNE -- Branch on not equal. ; Branches if the two registers are not equal. ; Operation: if $s != $t advance_pc(offset << 2)); ; else advance_pc(4); ; Syntax: bne $s, $t, offset ; Encoding: 0001 01ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_bne: IType ; Load Imm, rS, rT Fields mov nPC, PC ; nPC := PC add nPC, 0x4 ; nPC := nPC + 4 SX18_4N Imm ; Sign Extend Imm * 4 mov TMP, R(rS) ; TMP := Regs[rS] cmp TMP, R(rT) ; CMP(TMP, Regs[rT]) mov TMP, 0x4 ; TMP := 4 cmovne TMP, Imm ; If Regs[rS] != Regs[rT], TMP := Imm add nPC, TMP ; nPC := nPC + TMP Flg_On InDelaySlot ; Set 'Delay Slot' Flag. jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; BLEZ -- Branch on less than or equal to zero. ; Branches if the register is less than or equal to zero ; Operation: if $s <= 0 advance_pc(offset << 2)); ; else advance_pc(4); ; Syntax: blez $s, offset ; Encoding: 0001 10ss sss0 0000 iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_blez: IType_I_S_Only ; load rS and Imm Fields mov nPC, PC ; nPC := PC add nPC, 0x4 ; nPC := nPC + 4 SX18_4N Imm ; Sign Extend Imm * 4 mov TMP, 0x4 ; TMP := 4 cmp R(rS), 0 ; If Regs[rS] <= 0: cmovle TMP, Imm ; ... then TMP := Imm add nPC, TMP ; nPC := nPC + TMP Flg_On InDelaySlot ; Set 'Delay Slot' Flag. jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; BGTZ -- Branch on greater than zero. ; Branches if the register is greater than zero ; Operation: if $s > 0 advance_pc(offset << 2)); ; else advance_pc(4); ; Syntax: bgtz $s, offset ; Encoding: 0001 11ss sss0 0000 iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_bgtz: IType_I_S_Only ; load rS and Imm Fields mov nPC, PC ; nPC := PC add nPC, 0x4 ; nPC := nPC + 4 SX18_4N Imm ; Sign Extend Imm * 4 mov TMP, 0x4 ; TMP := 4 cmp R(rS), 0 ; If Regs[rS] > 0: cmovg TMP, Imm ; ... then TMP := Imm add nPC, TMP ; nPC := nPC + TMP Flg_On InDelaySlot ; Set 'Delay Slot' Flag. jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; ADDI -- Add immediate (with overflow). ; Adds a register and a sign-extended immediate value and stores the ; result in a register ; Operation: $t = $s + imm; advance_pc(4); ; Syntax: addi $t, $s, imm ; Encoding: 0010 00ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- ; TODO: untested align GRAIN, db 0x90 _i_addi: ; UNDONE_INST IType ; Load Imm, rS, rT Fields SX16 Imm ; Sign-extend the Imm offset mov TMP, R(rS) ; TMP := Regs[rS] add TMP, Imm ; TMP := TMP + Imm ; TODO: detect and trap overflow Wr_Reg rT, TMP ; Regs[rT] := TMP (result) jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; ADDIU -- Add immediate unsigned (no overflow). ; Adds a register and a sign-extended immediate value and stores the ; result in a register ; Operation: $t = $s + imm; advance_pc(4); ; Syntax: addiu $t, $s, imm ; Encoding: 0010 01ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_addiu: IType ; Load Imm, rS, rT Fields SX16 Imm ; Sign-extend the Imm offset mov TMP, R(rS) ; TMP := Regs[rS] add TMP, Imm ; TMP := TMP + Imm Wr_Reg rT, TMP ; Regs[rT] := TMP (result) jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; SLTI -- Set on less than immediate (signed). ; If $s is less than immediate, $t is set to one. It gets zero otherwise. ; Operation: if $s < imm $t = 1; advance_pc(4); ; else $t = 0; advance_pc(4); ; Syntax: slti $t, $s, imm ; Encoding: 0010 10ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_slti: IType ; Load Imm, rS, rT Fields SX16 Imm ; Sign-extend the Imm offset xor TMP, TMP ; Clear TMP cmp R(rS), Imm ; CMP(R(rS), Imm) setl TMP_LowByte ; if $s <(sgn) imm then TMP := 1; else 0 Wr_Reg rT, TMP ; Regs[rT] := TMP (result) jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; SLTIU -- Set on less than immediate unsigned. ; If $s is less than the unsigned immediate, $t is set to one. ; It gets zero otherwise. ; Operation: if $s < imm $t = 1; advance_pc(4); ; else $t = 0; advance_pc(4); ; Syntax: sltiu $t, $s, imm ; Encoding: 0010 11ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- ; Apparently even here we sign-extend the immediate. align GRAIN, db 0x90 _i_sltiu: IType ; Load Imm, rS, rT Fields SX16 Imm ; Sign-extend the Imm offset xor TMP, TMP ; Clear TMP cmp R(rS), Imm ; CMP(R(rS), Imm) setb TMP_LowByte ; if $s < imm then TMP := 1; else 0 Wr_Reg rT, TMP ; Regs[rT] := TMP (result) jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; ANDI -- Bitwise AND immediate. ; Bitwise ANDs a register and an immediate value and stores the result ; in a register ; Operation: $t = $s & imm; advance_pc(4); ; Syntax: andi $t, $s, imm ; Encoding: 0011 00ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_andi: IType ; Load Imm, rS, rT Fields mov TMP, R(rS) ; TMP := Regs[rS] and TMP, Imm ; TMP := TMP & Imm Wr_Reg rT, TMP ; Regs[rT] := TMP (result) jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; ORI -- Bitwise OR immediate. ; Bitwise OrS a register and an immediate value and stores the result ; in a register ; Operation: $t = $s | imm; advance_pc(4); ; Syntax: ori $t, $s, imm ; Encoding: 0011 01ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_ori: IType ; Load Imm, rS, rT Fields mov TMP, R(rS) ; TMP := Regs[rS] or TMP, Imm ; TMP := TMP | Imm Wr_Reg rT, TMP ; Regs[rT] := TMP (result) jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; XORI -- Bitwise Exclusive Or immediate. ; Bitwise XOrS a register and an immediate value and stores the ; result in a register ; Operation: $t = $s ^ imm; advance_pc(4); ; Syntax: xori $t, $s, imm ; Encoding: 0011 10ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_xori: IType ; Load Imm, rS, rT Fields mov TMP, R(rS) ; TMP := Regs[rS] xor TMP, Imm ; TMP := TMP ^ Imm Wr_Reg rT, TMP ; Regs[rT] := TMP (result) jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; LUI -- Load upper immediate. ; The immediate value is shifted left 16 bits and stored in the register. ; The lower 16 bits are zeroes. ; Operation: $t = (imm << 16); advance_pc(4); ; Syntax: lui $t, imm ; Encoding: 0011 11-- ---t tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_lui: IType_I_T_Only ; Load Imm and rT Fields mov TMP, Imm ; TMP := Imm shl TMP, 16 ; TMP := TMP << 16 Wr_Reg rT, TMP ; Regs[rT] := TMP (result) jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; BEQL - Branch on Equal Likely. ; Compare registers, then do a PC-relative conditional branch; ; execute the delay slot only if the branch is taken. ; An 18-bit signed offset (the 16-bit offset field shifted left 2 bits) is ; added to the address of the instruction following the branch (not the ; branch itself), in the branch delay slot, to form a PC-relative effective ; target address. If the contents of rS and rT are equal, branch to the target ; address after the instruction in the delay slot is executed. If the branch ; is not taken, the instruction in the delay slot is not executed. ; Operation: if rS = rT then branch_likely ; Syntax: beql $s, $t, offset ; Encoding: 0101 00ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_beql: IType ; Load Imm, rS, rT Fields mov TMP, R(rS) ; TMP := Regs[rS] cmp TMP, R(rT) ; CMP(TMP, Regs[rT]) jne _i_beql_not_taken ; If !(TMP = Regs[rT]) then NotTaken ; Taken: SX18_4N Imm ; Sign Extend Imm * 4 mov nPC, PC ; nPC := PC add nPC, 0x4 ; nPC := nPC + 4 add nPC, Imm ; nPC := nPC + Offset Flg_On InDelaySlot ; Set 'Delay Slot' Flag. jmp _end_cycle ; Not Taken: _i_beql_not_taken: add PC, 0x4 ; PC := PC + 4 jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; BNEL - Branch on Not Equal Likely. ; Compare registers, then do a PC-relative conditional branch; ; execute the delay slot only if the branch is taken. ; An 18-bit signed offset (the 16-bit offset field shifted left 2 bits) is ; added to the address of the instruction following the branch (not the ; branch itself), in the branch delay slot, to form a PC-relative effective ; target address. If the contents of rS and rT are NOT equal, branch to the ; target address after the instruction in the delay slot is executed. If the ; branch is not taken, the instruction in the delay slot is not executed. ; Operation: if rS != rT then branch_likely ; Syntax: bnel $s, $t, offset ; Encoding: 0101 01ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_bnel: IType ; Load Imm, rS, rT Fields mov TMP, R(rS) ; TMP := Regs[rS] cmp TMP, R(rT) ; CMP(TMP, Regs[rT]) je _i_bnel_not_taken ; If !(TMP != Regs[rT]) then NotTaken ; Taken: SX18_4N Imm ; Sign Extend Imm * 4 mov nPC, PC ; nPC := PC add nPC, 0x4 ; nPC := nPC + 4 add nPC, Imm ; nPC := nPC + Offset Flg_On InDelaySlot ; Set 'Delay Slot' Flag. jmp _end_cycle ; Not Taken: _i_bnel_not_taken: add PC, 0x4 ; PC := PC + 4 jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; BLEZL - Branch on Less Than or Equal to Zero Likely. ; Test a register, then do a PC-relative conditional branch; ; execute the delay slot only if the branch is taken. ; An 18-bit signed offset (the 16-bit offset field shifted left 2 bits) is ; added to the address of the instruction following the branch (not the branch ; itself), in the branch delay slot, to form a PC-relative effective target ; address. If the contents of rS are less than or equal to zero (sign bit is ; 1 or value is zero), branch to the effective target address after the ; instruction in the delay slot is executed. If the branch is not taken, the ; instruction in the delay slot is not executed. ; Operation: If rS <= 0 then branch_likely ; Syntax: bltzl $s, offset ; Encoding: 0101 10ss sss0 0000 iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_blezl: IType_S_Only ; load only rS Field just now cmp R(rS), 0 ; CMP(Regs[rS], 0) jnle _i_blezl_not_taken ; If !(Regs[rS] <= 0) then NotTaken ; Taken: IType_I_Only ; load only Imm Field just now SX18_4N Imm ; Sign Extend Imm * 4 mov nPC, PC ; nPC := PC add nPC, 0x4 ; nPC := nPC + 4 add nPC, Imm ; nPC := nPC + Offset Flg_On InDelaySlot ; Set 'Delay Slot' Flag. jmp _end_cycle ; Not Taken: _i_blezl_not_taken: add PC, 0x4 ; PC := PC + 4 jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; BGTZL - Branch on Greater Than Zero Likely. ; Test a register, then do a PC-relative conditional branch; ; execute the delay slot only if the branch is taken. ; An 18-bit signed offset (the 16-bit offset field shifted left 2 bits) is ; added to the address of the instruction following the branch (not the branch ; itself), in the branch delay slot, to form a PC-relative effective target ; address. If the contents of rS are greater than zero (sign bit is 0 but ; value not zero), branch to the effective target address after the ; instruction in the delay slot is executed. If the branch is not taken, the ; instruction in the delay slot is not executed. ; Operation: If rS > 0 then branch_likely ; Syntax: bgtzl $s, offset ; Encoding: 0101 11ss sss0 0000 iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_bgtzl: IType_S_Only ; load only rS Field just now cmp R(rS), 0 ; CMP(Regs[rS], 0) jng _i_bgtzl_not_taken ; If !(Regs[rS] > 0) then NotTaken ; Taken: IType_I_Only ; load only Imm Field just now SX18_4N Imm ; Sign Extend Imm * 4 mov nPC, PC ; nPC := PC add nPC, 0x4 ; nPC := nPC + 4 add nPC, Imm ; nPC := nPC + Offset Flg_On InDelaySlot ; Set 'Delay Slot' Flag. jmp _end_cycle ; Not Taken: _i_bgtzl_not_taken: add PC, 0x4 ; PC := PC + 4 jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; MUL - Multiply Word to Register. ; The 32-bit word value in rS is multiplied by the 32-bit value in rT, ; treating both operands as signed values, to produce a 64-bit result. ; The least significant 32 bits of the product are written to rD. ; The contents of HI and LO are UNPREDICTABLE after the operation. ; No arithmetic exception occurs under any circumstances. ; Syntax: mul $d, $s, $t ; Encoding: 0111 00ss ssst tttt dddd d000 0000 0010 ;----------------------------------------------------------------------------- ; TODO: untested align GRAIN, db 0x90 _i_mul: RType ; load rD, rS, rT Fields mov TMP, R(rT) ; TMP := Regs[rT] imul TMP, R(rS) ; TMP := TMP * Regs[rS] (Bottom 32 bits) Wr_Reg rD, TMP ; Regs[rD] := Bottom 32 bits of prod jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; LB -- Load Byte. ; A byte is loaded into a register from the specified address. ; Operation: $t = MEM[$s + offset]; advance_pc(4); ; Syntax: lb $t, offset($s) ; Encoding: 1000 00ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_lb: IType ; Load Imm, rS, rT Fields SX16 Imm ; Sign-extend the Imm offset add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr) call _Virt_Read_Byte ; AL := Virt_Read_Byte(EAX) shl eax, 24 ; Shift left for sign-extension: sar eax, 24 ; Shift back right, dragging sign bit: Wr_Reg rT, EAX ; Regs[rT] := EAX jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; LH - Load Halfword. ; Load a halfword from memory as a signed value. ; The contents of the 16-bit halfword at the memory location specified by the ; aligned effective address are fetched, sign-extended, and placed in rT. ; The 16-bit signed offset is added to the contents of rS to form the ; effective address. The effective address must be naturally-aligned. ; If the least-significant bit of the address is non-zero, an Address ; Error exception occurs ; Operation: $t = MEM[$s + offset]; advance_pc(4); ; Syntax: lh $t, offset($s) ; Encoding: 1000 01ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- ; NOTE: LHU is exactly same thing as LH, but without sign-extend. align GRAIN, db 0x90 _i_lh: IType ; Load Imm, rS, rT Fields SX16 Imm ; Sign-extend the Imm offset add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr) ;; rS (ecx) is not needed any more, can be reused bt Imm, 0 ; Get low bit of vAddr jnc _i_lh_aligned_ok ; If zero, vAddr was properly aligned; SetEXC EXC_AdEL ; If vAddr was NOT properly aligned: jmp _Handle_Exception ; Go straight to exception handler. _i_lh_aligned_ok: ; Load is to proceed normally: mov ecx, Imm ; Save vAddr to ECX xor TMP, TMP ; Clear TMP, where we will put the HW %ifdef LITTLE_ENDIAN ;; Read the low byte of the HW first: call _Virt_Read_Byte ; EAX := Virt_Read_Byte(vAddr) mov TMP, eax ; TMP := eax (save the low byte) ;; Now read the high byte: mov eax, ecx ; Restore the original saved vAddr or eax, 1 ; Will read vAddr + 1 call _Virt_Read_Byte ; EAX := Virt_Read_Byte(vAddr + 1) %else or Imm, 1 ; First, read vAddr + 1 : call _Virt_Read_Byte ; EAX := Virt_Read_Byte(vAddr + 1) mov TMP, eax ; TMP := eax (save low byte) mov eax, ecx ; Restore the original saved vAddr call _Virt_Read_Byte ; EAX := Virt_Read_Byte(vAddr) %endif shl eax, 8 ; eax := eax << 8 or eax, TMP ; eax := eax | TMP (high | low) shl eax, 16 ; left shift eax to put the HW on top sar eax, 16 ; right shift it back, to sign-extend. Wr_Reg rT, eax ; Regs[rT] := EAX (write back result) jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; LWL - Load Word Left. ; Load the most-significant part of a word as a signed value from an unaligned ; memory address. ; Operation: $t = $t MERGE MEM[$s + offset]; advance_pc(4); ; Syntax: lwl $t, offset($s) ; Encoding: 1000 10ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_lwl: IType ; Load Imm, rS, rT Fields SX16 Imm ; Sign-extend the Imm offset add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr) ;; rS (ecx) is not needed any more, can be reused mov TMP, R(rT) ; TMP := Regs[rT] (old reg value) mov AUX, Imm ; Save the original unaligned address and Imm, ~(0x3) ; Clear bottom two bits of address call _Virt_Read_Word ; EAX := Virt_Read_Word(EAX (aligned)) ;; Proceed with write. EAX : old word, TMP : new word, ebx : still rT mov ecx, AUX ; ecx := original unaligned address and ecx, 0x3 ; keep only bottom two bits of it shl ecx, 3 ; ecx := ecx (8 * (addr[0..2])) shl eax, cl ; left shift eax (orig word) by above xor ecx, 24 ; ecx := 24 - ecx mov AUX, 0xFFFFFF ; AUX := 0xFFFFFF shr AUX, cl ; AUX := AUX >> cl and TMP, AUX ; TMP := TMP & AUX or TMP, eax ; TMP := TMP | eax (the writeback value) Wr_Reg rT, TMP ; Regs[rT] := TMP (the writeback value) jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; LW -- Load Word. ; The contents of the 32-bit word at the memory location specified by the ; aligned effective address are fetched, signextended to the register length ; if necessary, and placed in register rT. The 16-bit signed offset is added ; to the contents of the base to form the effective address. ; Operation: $t = MEM[$s + offset]; advance_pc(4); ; Syntax: lw $t, offset($s) ; Encoding: 1000 11ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_lw: IType ; Load Imm, rS, rT Fields SX16 Imm ; Sign-extend the Imm offset add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr) call _Virt_Read_Word ; EAX := Virt_Read_Word(EAX) Wr_Reg rT, EAX ; Regs[rT] := EAX jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; LBU - Load Byte Unsigned. ; Load a byte from memory as an unsigned value. ; The contents of the 8-bit byte at the memory location specified by the ; effective address are fetched, zero-extended, and placed in rT. ; The 16-bit signed offset is added to the contents of rS to form the ; effective address. ; Operation: $t = MEM[$s + offset]; advance_pc(4); ; Syntax: lbu $t, offset($s) ; Encoding: 1001 00ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_lbu: IType ; Load Imm, rS, rT Fields SX16 Imm ; Sign-extend the Imm offset add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr) call _Virt_Read_Byte ; AL := Virt_Read_Byte(EAX) Wr_Reg rT, EAX ; Regs[rT] := EAX jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; LHU - Load Halfword Unsigned. ; Load a halfword from memory as an unsigned value. ; The contents of the 16-bit halfword at the memory location specified by the ; aligned effective address are fetched, zero-extended, and placed in reg rT. ; The 16-bit signed offset is added to the contents of register rS to form the ; effective address. The effective address must be naturally-aligned. ; If the least-significant bit of the address is non-zero, ; an Address Error exception occurs. ; Operation: $t = MEM[$s + offset]; advance_pc(4); ; Syntax: lhu $t, offset($s) ; Encoding: 1001 01ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- ; NOTE: exactly same thing as LH, but WITHOUT sign-extend. align GRAIN, db 0x90 _i_lhu: IType ; Load Imm, rS, rT Fields SX16 Imm ; Sign-extend the Imm offset add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr) ;; rS (ecx) is not needed any more, can be reused bt Imm, 0 ; Get low bit of vAddr jnc _i_lhu_aligned_ok ; If zero, vAddr was properly aligned; SetEXC EXC_AdEL ; If vAddr was NOT properly aligned: jmp _Handle_Exception ; Go straight to exception handler. _i_lhu_aligned_ok: ; Load is to proceed normally: mov ecx, Imm ; Save vAddr to ECX xor TMP, TMP ; Clear TMP, where we will put the HW %ifdef LITTLE_ENDIAN ;; Read the low byte of the HW first: call _Virt_Read_Byte ; EAX := Virt_Read_Byte(vAddr + 1) mov TMP, eax ; TMP := eax (save the low byte) ;; Now read the high byte: mov eax, ecx ; Restore the original saved vAddr or eax, 1 ; Will read vAddr + 1 call _Virt_Read_Byte ; EAX := Virt_Read_Byte(vAddr + 1) %else or Imm, 1 ; First, read vAddr + 1 : call _Virt_Read_Byte ; EAX := Virt_Read_Byte(vAddr + 1) mov TMP, eax ; TMP := eax (save low byte) mov eax, ecx ; Restore the original saved vAddr call _Virt_Read_Byte ; EAX := Virt_Read_Byte(vAddr) %endif shl eax, 8 ; eax := eax << 8 or eax, TMP ; eax := eax | TMP (high | low) Wr_Reg rT, eax ; Regs[rT] := EAX (write back result) jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; LWL - Load Word Right. ; Load the least-significant part of a word from an unaligned memory address ; as a signed value. The 16-bit signed offset is added to the contents of rS ; to form an effective address (EffAddr). EffAddr is the address of the ; least-significant of 4 consecutive bytes forming a word (W) in memory ; starting at an arbitrary byte boundary. A part of W, the least-significant ; 1 to 4 bytes, is in the aligned word containing EffAddr. This part of W is ; loaded into the least-significant (right) part of the word in register rT. ; The remaining most-significant part of the word in register rT is unchanged. ; Executing both LWR and LWL, in either order, delivers a sign-extended word ; value in the destination register. ; Operation: $t = $t MERGE MEM[$s + offset]; advance_pc(4); ; Syntax: lwr $t, offset($s) ; Encoding: 1001 10ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_lwr: IType ; Load Imm, rS, rT Fields SX16 Imm ; Sign-extend the Imm offset add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr) ;; rS (ecx) is not needed any more, can be reused mov TMP, R(rT) ; TMP := Regs[rT] (value to write) mov AUX, Imm ; Save the original unaligned address and Imm, ~(0x3) ; Clear bottom two bits of address call _Virt_Read_Word ; EAX := Virt_Read_Word(EAX (aligned)) ;; Proceed with write. EAX : old word, TMP : new word, ebx : still rT mov ecx, AUX ; ecx := original unaligned address and ecx, 0x3 ; keep only bottom two bits of it shl ecx, 3 ; ecx := ecx (8 * (addr[0..2])) mov AUX, 0xFFFFFF00 ; AUX := 0xFFFFFF00 shl AUX, cl ; AUX := AUX << cl and TMP, AUX ; TMP := TMP & AUX xor ecx, 24 ; ecx := 24 - ecx shr eax, cl ; right shift eax (orig word) by above or TMP, eax ; TMP := TMP | eax (the writeback value) Wr_Reg rT, TMP ; Regs[rT] := TMP (the writeback value) jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; SB -- Store Byte. ; The least significant byte of $t is stored at the specified address. ; Operation: MEM[$s + offset] = (0xff & $t); advance_pc(4); ; Syntax: sb $t, offset($s) ; Encoding: 1010 00ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_sb: IType ; Load Imm, rS, rT Fields SX16 Imm ; Sign-extend the Imm offset add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr) mov TMP, R(rT) ; TMP (EDX) := Regs[rT] and TMP, 0xFF ; Keep only low byte of TMP call _Virt_Write_Byte ; Virt_Write_Byte(EAX, DL) jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; SH - Store Halfword. ; Store a halfword to memory. The least-significant 16-bit halfword of ; register rT is stored in memory at the location specified by the aligned ; effective address. The 16-bit signed offset is added to the contents of rS ; to form the effective address. ; The effective address must be naturally-aligned. If the least-significant ; bit of the address is non-zero, an Address Error exception occurs. ; Operation: MEM[$s + offset] = $t; advance_pc(4); ; Syntax: sh $t, offset($s) ; Encoding: 1010 01ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_sh: IType ; Load Imm, rS, rT Fields SX16 Imm ; Sign-extend the Imm offset add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr) bt Imm, 0 ; Get low bit of vAddr jnc _i_sh_aligned_ok ; If zero, vAddr was properly aligned; SetEXC EXC_AdES ; If vAddr was NOT properly aligned: jmp _Handle_Exception ; Go straight to exception handler. _i_sh_aligned_ok: mov AUX, Imm ; Save Imm (vAddr) to AUX ;; rS (ecx) is not needed any more, can be reused mov ecx, R(rT) ; ecx := Regs[rT] (HW to be written) mov TMP, ecx ; TMP := ecx %ifdef LITTLE_ENDIAN and TMP, 0xFF ; isolate low byte call _Virt_Write_Byte ; Virt_Write_Byte(vAddr, DL) mov TMP, ecx ; TMP := the whole HW again and TMP, 0xFF00 ; isolate high byte shr TMP, 8 ; TMP := TMP >> 8 (get high byte) %else ;; Big-Endian shr TMP, 8 ; TMP := TMP >> 8 (get high byte) call _Virt_Write_Byte ; Virt_Write_Byte(vAddr, DL) mov TMP, ecx ; TMP := ecx again, now for low byte and TMP, 0xFF ; isolate low byte %endif mov eax, AUX ; restore vAddr from AUX or eax, 1 ; set bottom bit, for vAddr + 1 call _Virt_Write_Byte ; Virt_Write_Byte(vAddr + 1, DL) jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; SWL - Store Word Left. ; Store the most-significant part of a word to an unaligned memory address. ; Operation: MEM[$s + offset] = $t; advance_pc(4); ; Syntax: swl $t, offset($s) ; Encoding: 1010 10ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_swl: IType ; Load Imm, rS, rT Fields SX16 Imm ; Sign-extend the Imm offset add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr) ;; rS (ecx) is not needed any more, can be reused mov TMP, R(rT) ; TMP := Regs[rT] (old reg value) ;; rT (ebx) is not needed any more, can be reused mov AUX, Imm ; Save the original unaligned address and Imm, ~(0x3) ; Clear bottom two bits of address mov ebx, Imm ; Save the aligned address for writeback call _Virt_Read_Word ; EAX := Virt_Read_Word(EAX (aligned)) ;; Proceed with write. EAX : old word, TMP : new word, ebx : WB addr. mov ecx, AUX ; ecx := original unaligned address and ecx, 0x3 ; keep only bottom two bits shl ecx, 3 ; ecx := ecx (8 * (addr[0..2])) shr TMP, cl ; right shift TMP by above xor ecx, 24 ; ecx := 24 - ecx mov AUX, 0xFFFFFF00 ; AUX := 0xFFFFFF00 shl AUX, cl ; AUX := AUX << cl and eax, AUX ; eax := eax & AUX or TMP, eax ; TMP := TMP | eax (the writeback value) mov eax, ebx ; restore aligned address for writeback call _Virt_Write_Word ; Virt_Write_Word(EAX, TMP) jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; SW -- Store Word. ; The contents of $t is stored at the specified address. ; The effective address must be naturally-aligned. ; If either of the 2 least-significant bits of the address is non-zero, ; an Address Error exception occurs. ; Operation: MEM[$s + offset] = $t; advance_pc(4); ; Syntax: sw $t, offset($s) ; Encoding: 1010 11ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_sw: IType ; Load Imm, rS, rT Fields SX16 Imm ; Sign-extend the Imm offset add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr) mov TMP, R(rT) ; TMP := Regs[rT] call _Virt_Write_Word ; Virt_Write_Word(EAX, TMP) jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; SWR - Store Word Right. ; Store the least-significant part of a word to an unaligned memory address. ; Operation: MEM[$s + offset] = $t; advance_pc(4); ; Syntax: swr $t, offset($s) ; Encoding: 1011 10ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_swr: IType ; Load Imm, rS, rT Fields SX16 Imm ; Sign-extend the Imm offset add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr) ;; rS (ecx) is not needed any more, can be reused mov TMP, R(rT) ; TMP := Regs[rT] (value to write) ;; rT (ebx) is not needed any more, can be reused mov AUX, Imm ; Save the original unaligned address and Imm, ~(0x3) ; Clear bottom two bits of address mov ebx, Imm ; Save the aligned address for writeback call _Virt_Read_Word ; EAX := Virt_Read_Word(EAX (aligned)) ;; Proceed with write. EAX : old word, TMP : new word, ebx : WB addr. mov ecx, AUX ; ecx := original unaligned address and ecx, 0x3 ; keep only bottom two bits shl ecx, 3 ; ecx := ecx * 8 mov AUX, 0xFFFFFF ; AUX := 0xFFFFFF shr AUX, cl ; AUX := AUX >> cl and eax, AUX ; eax := eax & AUX xor ecx, 24 ; ecx := 24 - ecx (24 - 8 * (addr[0..2])) shl TMP, cl ; left shift TMP (value to write) by above or TMP, eax ; TMP := TMP | eax (the writeback value) mov eax, ebx ; restore aligned address for writeback call _Virt_Write_Word ; Virt_Write_Word(EAX, TMP) jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; CACHE. ; Operation: This is a NOP in this emulator. ; Syntax: cache $t, offset($s) ; Encoding: 1011 11ss ssst tttt iiii iiii iiii iiii ; PRIVILEGED (permitted in Kernel Mode only.) ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_cache: ; no fields PRIVILEGED ; Permitted in Kernel Mode only. jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; LL - Load Linked Word. ; Load a word from memory for an atomic read-modify-write. ; The contents of the 32-bit word at the memory location specified by the ; aligned effective address are fetched and written into register rT. ; The 16-bit signed offset is added to the contents of rS to form ; an effective address. ; Operation: $t = MEM[$s + offset]; llbit = 1; advance_pc(4); ; Syntax: ll $t, offset($s) ; Encoding: 1100 00ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_ll: IType ; Load Imm, rS, rT Fields SX16 Imm ; Sign-extend the Imm offset add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr) call _Virt_Read_Word ; EAX := Virt_Read_Word(EAX) Wr_Reg rT, EAX ; Regs[rT] := EAX Flg_On LL_Bit ; Set the LL_Bit Flag jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; PREF - Prefetch. ; Operation: This is a NOP in this emulator. ; Syntax: pref $t, offset($s) ; Encoding: 1100 11ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_pref: ; no fields jmp _end_cycle ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; SC - Store Conditional Word. ; Store a word to memory to complete an atomic read-modify-write. ; The 32-bit word in rT is conditionally stored in memory at the location ; specified by the aligned effective address. ; The 16-bit signed offset is added to the contents of rS to form an ; effective address ; Operation: if llbit == 1 then: MEM[$s + offset] = $t; rt = 1; advance_pc(4); ; else: rt = 0; advance_pc(4); ; Syntax: sc $t, offset($s) ; Encoding: 1110 00ss ssst tttt iiii iiii iiii iiii ;----------------------------------------------------------------------------- align GRAIN, db 0x90 _i_sc: IType ; Load Imm, rS, rT Fields Flg_Get LL_Bit ; CF := LL_Bit jnc _i_sc_not_taken ; If LL_Bit = 0, then do not store; else: SX16 Imm ; Sign-extend the Imm offset add Imm, R(rS) ; Imm (EAX) := Imm + Regs[rS] (vAddr) mov TMP, R(rT) ; TMP := Regs[rT] call _Virt_Write_Word ; Virt_Write_Word(EAX, TMP) mov R(rT), 1 ; Regs[rT] := 1 ('yes, stored word') jmp _i_sc_done ; Done. _i_sc_not_taken: mov R(rT), 0 ; Regs[rT] := 0 ('no, did not store') _i_sc_done: jmp _end_cycle ;-----------------------------------------------------------------------------