raw
m_genesis.kv            1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
m_genesis.kv 2 ;; ;;
m_genesis.kv 3 ;; This file is part of 'M', a MIPS system emulator. ;;
m_genesis.kv 4 ;; ;;
m_genesis.kv 5 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
m_genesis.kv 6 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
m_genesis.kv 7 ;; ;;
m_genesis.kv 8 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
m_genesis.kv 9 ;; distribute this software ; Should you use this software for any purpose, ;;
m_genesis.kv 10 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
m_genesis.kv 11 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
m_genesis.kv 12 ;; continue doing so for the indefinite future. In any case, please ;;
m_genesis.kv 13 ;; always : read and understand any software ; verify any PGP signatures ;;
m_genesis.kv 14 ;; that you use - for any purpose. ;;
m_genesis.kv 15 ;; ;;
m_genesis.kv 16 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
m_genesis.kv 17 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
m_genesis.kv 18
m_genesis.kv 19 ;; TODO: Tests!!!
m_genesis.kv 20
m_genesis.kv 21 ;-----------------------------------------------------------------------------
m_genesis.kv 22 section .rodata
m_genesis.kv 23 align GRAIN, db 0x90
m_genesis.kv 24 _M_Table:
m_genesis.kv 25 A32 _bad ; 0x00 : UNDEFINED
m_genesis.kv 26 A32 _bad ; 0x01 : UNDEFINED
m_genesis.kv 27 A32 _m_tlbwi ; 0x02 : tlbwi (01000010000000000000000000000010)
m_genesis.kv 28 A32 _bad ; 0x03 : UNDEFINED
m_genesis.kv 29 A32 _bad ; 0x04 : UNDEFINED
m_genesis.kv 30 A32 _bad ; 0x05 : UNDEFINED
m_genesis.kv 31 A32 _m_tlbwr ; 0x06 : tlbwr (01000010000000000000000000000110)
m_genesis.kv 32 A32 _bad ; 0x07 : UNDEFINED
m_genesis.kv 33 A32 _m_tlbp ; 0x08 : tlbp (01000010000000000000000000001000)
m_genesis.kv 34 A32 _bad ; 0x09 : UNDEFINED
m_genesis.kv 35 A32 _bad ; 0x0a : UNDEFINED
m_genesis.kv 36 A32 _bad ; 0x0b : UNDEFINED
m_genesis.kv 37 A32 _bad ; 0x0c : UNDEFINED
m_genesis.kv 38 A32 _bad ; 0x0d : UNDEFINED
m_genesis.kv 39 A32 _bad ; 0x0e : UNDEFINED
m_genesis.kv 40 A32 _bad ; 0x0f : UNDEFINED
m_genesis.kv 41 A32 _bad ; 0x10 : UNDEFINED
m_genesis.kv 42 A32 _bad ; 0x11 : UNDEFINED
m_genesis.kv 43 A32 _bad ; 0x12 : UNDEFINED
m_genesis.kv 44 A32 _bad ; 0x13 : UNDEFINED
m_genesis.kv 45 A32 _bad ; 0x14 : UNDEFINED
m_genesis.kv 46 A32 _bad ; 0x15 : UNDEFINED
m_genesis.kv 47 A32 _bad ; 0x16 : UNDEFINED
m_genesis.kv 48 A32 _bad ; 0x17 : UNDEFINED
m_genesis.kv 49 A32 _m_eret ; 0x18 : eret (01000010000000000000000000011000)
m_genesis.kv 50 A32 _bad ; 0x19 : UNDEFINED
m_genesis.kv 51 A32 _bad ; 0x1a : UNDEFINED
m_genesis.kv 52 A32 _bad ; 0x1b : UNDEFINED
m_genesis.kv 53 A32 _bad ; 0x1c : UNDEFINED
m_genesis.kv 54 A32 _bad ; 0x1d : UNDEFINED
m_genesis.kv 55 A32 _bad ; 0x1e : UNDEFINED
m_genesis.kv 56 A32 _bad ; 0x1f : UNDEFINED
m_genesis.kv 57 ;-----------------------------------------------------------------------------
m_genesis.kv 58
m_genesis.kv 59 section .text
m_genesis.kv 60
m_genesis.kv 61 ;-----------------------------------------------------------------------
m_genesis.kv 62 ; 'M-Type' Instructions (tlbwi, tlbwr, tlbp, eret, mfc0, mtc0, wait) : |
m_genesis.kv 63 ;-----------------------------------------------------------------------
m_genesis.kv 64
m_genesis.kv 65 ;-----------------------------------------------------------------------------
m_genesis.kv 66 ; TLBWI - Write Indexed TLB Entry.
m_genesis.kv 67 ; Write a TLB entry indexed by the Index register.
m_genesis.kv 68 ; The TLB entry pointed to by the Index register is written from the contents
m_genesis.kv 69 ; of the EntryHi, EntryLo0, EntryLo1, and PageMask registers.
m_genesis.kv 70 ; Syntax: tlbwi
m_genesis.kv 71 ; Encoding: 0100 0010 0000 0000 0000 0000 0000 0010
m_genesis.kv 72 ; PRIVILEGED (permitted in Kernel Mode only.)
m_genesis.kv 73 ;-----------------------------------------------------------------------------
m_genesis.kv 74 align GRAIN, db 0x90
m_genesis.kv 75 _m_tlbwi:
m_genesis.kv 76 ; no fields
m_genesis.kv 77 mov AUX, Sr(CP0_Index) ; Get CP0_Index register
m_genesis.kv 78 call _write_tlb_entry ; Write the indexed TLB entry.
m_genesis.kv 79 jmp _end_cycle
m_genesis.kv 80 ;-----------------------------------------------------------------------------
m_genesis.kv 81
m_genesis.kv 82 ;-----------------------------------------------------------------------------
m_genesis.kv 83 ; TLBWR - Write Random TLB Entry.
m_genesis.kv 84 ; Write a TLB entry indexed by the Random register.
m_genesis.kv 85 ; The TLB entry pointed to by the Random register is written from the contents
m_genesis.kv 86 ; of the EntryHi, EntryLo0, EntryLo1, and PageMask registers.
m_genesis.kv 87 ; Syntax: tlbwr
m_genesis.kv 88 ; Encoding: 0100 0010 0000 0000 0000 0000 0000 0110
m_genesis.kv 89 ; PRIVILEGED (permitted in Kernel Mode only.)
m_genesis.kv 90 ;-----------------------------------------------------------------------------
m_genesis.kv 91 align GRAIN, db 0x90
m_genesis.kv 92 _m_tlbwr:
m_genesis.kv 93 ; no fields
m_genesis.kv 94 mov ecx, Sr(CP0_Wired) ; ecx := CP0_Wired
m_genesis.kv 95 mov ebx, TLB_ENTRIES_COUNT ; ebx := #tlbentries
m_genesis.kv 96 sub ebx, ecx ; ebx := #tlbentries - Wired
m_genesis.kv 97 mov edx, 0 ; edx (upper half of dividend) := 0
m_genesis.kv 98 mov eax, CP0_Count ; eax (lower half of divident) := cnt
m_genesis.kv 99 div ebx ; edx:eax / ebx
m_genesis.kv 100 add edx, ecx ; edx (remainder) := edx + wired
m_genesis.kv 101 mov AUX, edx ; make edx the index for tlb write
m_genesis.kv 102 call _write_tlb_entry ; Write the indexed TLB entry.
m_genesis.kv 103 jmp _end_cycle
m_genesis.kv 104 ;-----------------------------------------------------------------------------
m_genesis.kv 105
m_genesis.kv 106 ;-----------------------------------------------------------------------------
m_genesis.kv 107 ; TLBP - Probe TLB for Matching Entry.
m_genesis.kv 108 ; Find a matching entry in the TLB.
m_genesis.kv 109 ; The Index register is loaded with the address of the TLB entry whose
m_genesis.kv 110 ; contents match the contents of the EntryHi register. If no TLB entry
m_genesis.kv 111 ; matches, the high-order bit of the Index register is set.
m_genesis.kv 112 ; Syntax: tlbp
m_genesis.kv 113 ; Encoding: 0100 0010 0000 0000 0000 0000 0000 1000
m_genesis.kv 114 ; PRIVILEGED (permitted in Kernel Mode only.)
m_genesis.kv 115 ;-----------------------------------------------------------------------------
m_genesis.kv 116 align GRAIN, db 0x90
m_genesis.kv 117 _m_tlbp:
m_genesis.kv 118 ; no fields
m_genesis.kv 119 mov Sr(CP0_Index), 0x80000000 ; CP0_Index := 0x80000000
m_genesis.kv 120 ;; Get the active ASID:
m_genesis.kv 121 mov edx, Sr(CP0_EntryHi) ; edx := CP0_EntryHi
m_genesis.kv 122 mov ecx, edx ; ecx := edx
m_genesis.kv 123 and edx, 0xFF ; edx := edx & 0xFF (get current ASID)
m_genesis.kv 124 ;; Get the desired tag:
m_genesis.kv 125 and ecx, 0xFFFFF000 ; ecx := ecx & 0xFFFFF000
m_genesis.kv 126 shr ecx, 13 ; ecx := ecx >> 13 (current Tag)
m_genesis.kv 127 ;; For each slot in table (0 .. 15), attempt lookup
m_genesis.kv 128 xor AUX, AUX ; Start with the 0-th entry in table
m_genesis.kv 129 _m_tlbp_lookup_entry:
m_genesis.kv 130 mov eax, TLB_E(AUX) ; eax := current TLB entry
m_genesis.kv 131 mov ebx, eax ; ebx := eax
m_genesis.kv 132 and ebx, TLB_VPN2_Mask ; get VPN2 of this entry
m_genesis.kv 133 cmp ebx, ecx ; cmp(entry.VPN2, vAddr.tag)
m_genesis.kv 134 jne _m_tlbp_lookup_nope ; if entry.VPN2 != vAddr.tag: no match
m_genesis.kv 135 bt eax, TLB_G ; is entry.G = 1?
m_genesis.kv 136 jc _m_tlbp_lookup_match ; then match.
m_genesis.kv 137 shr eax, TLB_ASID_Shift ; eax := eax >> TLB_ASID_Shift
m_genesis.kv 138 and eax, TLB_ASID_Mask ; eax := entry.ASID
m_genesis.kv 139 cmp eax, edx ; entry.ASID = current ASID ?
m_genesis.kv 140 jne _m_tlbp_lookup_nope ; if neither G=1 nor ASID match.
m_genesis.kv 141 ;; otherwise:
m_genesis.kv 142 _m_tlbp_lookup_match: ; TLB Match:
m_genesis.kv 143 mov Sr(CP0_Index), AUX ; Save the index
m_genesis.kv 144 jmp _end_cycle ; Fin.
m_genesis.kv 145 _m_tlbp_lookup_nope: ; try next one in the table, if any
m_genesis.kv 146 inc AUX ; index := index + 1
m_genesis.kv 147 cmp AUX, TLB_ENTRIES_COUNT ; see if still in range 0 .. n-1
m_genesis.kv 148 jb _m_tlbp_lookup_entry ; if in range, go to next entry
m_genesis.kv 149 ;; if we found nothing, we end up with CP0_Index = 0x80000000
m_genesis.kv 150 jmp _end_cycle ; Fin.
m_genesis.kv 151 ;-----------------------------------------------------------------------------
m_genesis.kv 152
m_genesis.kv 153 ;-----------------------------------------------------------------------------
m_genesis.kv 154 ; ERET - Exception Return.
m_genesis.kv 155 ; Return from interrupt, exception, or error trap.
m_genesis.kv 156 ; Syntax: eret
m_genesis.kv 157 ; Encoding: 0100 0010 0000 0000 0000 0000 0001 1000
m_genesis.kv 158 ; PRIVILEGED (permitted in Kernel Mode only.)
m_genesis.kv 159 ;;-----------------------------------------------------------------------------
m_genesis.kv 160 align GRAIN, db 0x90
m_genesis.kv 161 _m_eret:
m_genesis.kv 162 ; no fields
m_genesis.kv 163 Flg_Get InDelaySlot ; CF := whether we are in delay slot
m_genesis.kv 164 jc _m_eret_abort ; ... if so, abort this instruction; else:
m_genesis.kv 165 ;; proceed:
m_genesis.kv 166 Flg_Off LL_Bit ; Clear the LL_Bit Flag
m_genesis.kv 167 btr CP0_Status, CP0St_ERL ; CF := CP0St_ERL Flag, and clear it
m_genesis.kv 168 jnc _m_eret_erl_false ; If ERL was not set, do erl_false; else:
m_genesis.kv 169 _m_eret_erl_true:
m_genesis.kv 170 mov PC, Sr(CP0_ErrorEpc) ; PC := CP0_ErrorEpc
m_genesis.kv 171 jmp _m_eret_done ; Done with this case
m_genesis.kv 172 _m_eret_erl_false:
m_genesis.kv 173 mov PC, Sr(CP0_Epc) ; PC := CP0_Epc
m_genesis.kv 174 btr CP0_Status, CP0St_EXL ; Clear the EXL Flag
m_genesis.kv 175 _m_eret_done:
m_genesis.kv 176 sub PC, 0x4 ; Counteract the usual PC = PC + 4
m_genesis.kv 177 _m_eret_abort:
m_genesis.kv 178 jmp _end_cycle
m_genesis.kv 179 ;-----------------------------------------------------------------------------
m_genesis.kv 180
m_genesis.kv 181 ;-----------------------------------------------------------------------------
m_genesis.kv 182 ; MFC0 - Move from Coprocessor 0.
m_genesis.kv 183 ; Move the contents of a coprocessor 0 register to a general register.
m_genesis.kv 184 ; The contents of the coprocessor 0 register specified by the combination of
m_genesis.kv 185 ; rd and sel (q) are loaded into general register rt. Note that not all
m_genesis.kv 186 ; coprocessor 0 registers support the sel field. In those instances, the sel
m_genesis.kv 187 ; field must be zero.
m_genesis.kv 188 ; Operation: $t = CPR[0, rD, q]
m_genesis.kv 189 ; Syntax: mfc0 $t, $d, q
m_genesis.kv 190 ; Encoding: 0100 0000 000t tttt dddd d000 0000 0qqq
m_genesis.kv 191 ; PRIVILEGED (permitted in Kernel Mode only.)
m_genesis.kv 192 ;-----------------------------------------------------------------------------
m_genesis.kv 193 align GRAIN, db 0x90
m_genesis.kv 194 _m_mfc0:
m_genesis.kv 195 CPType ; Load Q, rD, rT (ecx, eax, ebx)
m_genesis.kv 196 JTABLE eax, _MFC0_Table ; Dispatch on rD via MFC0 Table.
m_genesis.kv 197 ;; We continue in _mfc0_rXX where XX is rD.
m_genesis.kv 198 ;-----------------------------------------------------------------------------
m_genesis.kv 199
m_genesis.kv 200 ;-----------------------------------------------------------------------------
m_genesis.kv 201 ; MFC0 Cases. Parameters: Q (ecx), rD (eax), rT (ebx)
m_genesis.kv 202 ;-----------------------------------------------------------------------------
m_genesis.kv 203 _mfc0_r00: ; 0x00
m_genesis.kv 204 test ecx, ecx ; Sel != 0 ?
m_genesis.kv 205 jnz _mfc0_unknown ; ... then unknown; else:
m_genesis.kv 206 mov TMP, Sr(CP0_Index) ; return CP0_Index
m_genesis.kv 207 jmp _mfc0_writeback ; Done
m_genesis.kv 208 ;-----------------------------------------------------------------------------
m_genesis.kv 209 _mfc0_r01: ; 0x01
m_genesis.kv 210 jmp _mfc0_unknown
m_genesis.kv 211 ;-----------------------------------------------------------------------------
m_genesis.kv 212 _mfc0_r02: ; 0x02
m_genesis.kv 213 mov TMP, Sr(CP0_EntryLo0) ; return CP0_EntryLo0
m_genesis.kv 214 jmp _mfc0_writeback ; Done
m_genesis.kv 215 ;-----------------------------------------------------------------------------
m_genesis.kv 216 _mfc0_r03: ; 0x03
m_genesis.kv 217 mov TMP, Sr(CP0_EntryLo1) ; return CP0_EntryLo1
m_genesis.kv 218 jmp _mfc0_writeback ; Done
m_genesis.kv 219 ;-----------------------------------------------------------------------------
m_genesis.kv 220 _mfc0_r04: ; 0x04
m_genesis.kv 221 test ecx, ecx ; Sel != 0 ?
m_genesis.kv 222 jnz _mfc0_unknown ; ... then unknown; else:
m_genesis.kv 223 mov TMP, Sr(CP0_Context) ; return CP0_Context
m_genesis.kv 224 jmp _mfc0_writeback ; Done
m_genesis.kv 225 ;-----------------------------------------------------------------------------
m_genesis.kv 226 _mfc0_r05: ; 0x05
m_genesis.kv 227 test ecx, ecx ; Sel != 0 ?
m_genesis.kv 228 jnz _mfc0_unknown ; ... then unknown; else:
m_genesis.kv 229 mov TMP, Sr(CP0_PageMask) ; return CP0_PageMask
m_genesis.kv 230 jmp _mfc0_writeback ; Done
m_genesis.kv 231 ;-----------------------------------------------------------------------------
m_genesis.kv 232 _mfc0_r06: ; 0x06
m_genesis.kv 233 test ecx, ecx ; Sel != 0 ?
m_genesis.kv 234 jnz _mfc0_unknown ; ... then unknown; else:
m_genesis.kv 235 mov TMP, Sr(CP0_Wired) ; return CP0_Wired
m_genesis.kv 236 jmp _mfc0_writeback ; Done
m_genesis.kv 237 ;-----------------------------------------------------------------------------
m_genesis.kv 238 _mfc0_r07: ; 0x07
m_genesis.kv 239 jmp _mfc0_unknown
m_genesis.kv 240 ;-----------------------------------------------------------------------------
m_genesis.kv 241 _mfc0_r08: ; 0x08
m_genesis.kv 242 test ecx, ecx ; Sel != 0 ?
m_genesis.kv 243 jnz _mfc0_unknown ; ... then unknown; else:
m_genesis.kv 244 mov TMP, Sr(CP0_BadVAddr) ; return CP0_BadVAddr
m_genesis.kv 245 jmp _mfc0_writeback ; Done
m_genesis.kv 246 ;-----------------------------------------------------------------------------
m_genesis.kv 247 _mfc0_r09: ; 0x09
m_genesis.kv 248 test ecx, ecx ; Sel != 0 ?
m_genesis.kv 249 jnz _mfc0_unknown ; ... then unknown; else:
m_genesis.kv 250 mov TMP, CP0_Count ; return CP0_Count ('fast reg')
m_genesis.kv 251 jmp _mfc0_writeback ; Done
m_genesis.kv 252 ;-----------------------------------------------------------------------------
m_genesis.kv 253 _mfc0_r10: ; 0x0a
m_genesis.kv 254 test ecx, ecx ; Sel != 0 ?
m_genesis.kv 255 jnz _mfc0_unknown ; ... then unknown; else:
m_genesis.kv 256 mov TMP, Sr(CP0_EntryHi) ; return CP0_EntryHi
m_genesis.kv 257 jmp _mfc0_writeback ; Done
m_genesis.kv 258 ;-----------------------------------------------------------------------------
m_genesis.kv 259 _mfc0_r11: ; 0x0b
m_genesis.kv 260 test ecx, ecx ; Sel != 0 ?
m_genesis.kv 261 jnz _mfc0_unknown ; ... then unknown; else:
m_genesis.kv 262 mov TMP, CP0_Compare ; return CP0_Compare ('fast reg')
m_genesis.kv 263 jmp _mfc0_writeback ; Done
m_genesis.kv 264 ;-----------------------------------------------------------------------------
m_genesis.kv 265 _mfc0_r12: ; 0x0c
m_genesis.kv 266 test ecx, ecx ; Sel != 0 ?
m_genesis.kv 267 jnz _mfc0_unknown ; ... then unknown; else:
m_genesis.kv 268 mov TMP, CP0_Status ; return CP0_Status ('fast reg')
m_genesis.kv 269 jmp _mfc0_writeback ; Done
m_genesis.kv 270 ;-----------------------------------------------------------------------------
m_genesis.kv 271 _mfc0_r13: ; 0x0d
m_genesis.kv 272 test ecx, ecx ; Sel != 0 ?
m_genesis.kv 273 jnz _mfc0_unknown ; ... then unknown; else:
m_genesis.kv 274 mov TMP, CP0_Cause ; return CP0_Cause ('fast reg')
m_genesis.kv 275 jmp _mfc0_writeback ; Done
m_genesis.kv 276 ;-----------------------------------------------------------------------------
m_genesis.kv 277 _mfc0_r14: ; 0x0e
m_genesis.kv 278 test ecx, ecx ; Sel != 0 ?
m_genesis.kv 279 jnz _mfc0_unknown ; ... then unknown; else:
m_genesis.kv 280 mov TMP, Sr(CP0_Epc) ; return CP0_Epc
m_genesis.kv 281 jmp _mfc0_writeback ; Done
m_genesis.kv 282 ;-----------------------------------------------------------------------------
m_genesis.kv 283 _mfc0_r15: ; 0x0f
m_genesis.kv 284 mov TMP, 0x00018000 ; processor id (qemu 4kc)
m_genesis.kv 285 jmp _mfc0_writeback ; Done
m_genesis.kv 286 ;-----------------------------------------------------------------------------
m_genesis.kv 287 _mfc0_r16: ; 0x10
m_genesis.kv 288 cmp r_Q, 0 ; Is sel = 0?
m_genesis.kv 289 je _mfc0_r16_q_0 ; If sel = 0...
m_genesis.kv 290 cmp r_Q, 1 ; Is sel = 1?
m_genesis.kv 291 je _mfc0_r16_q_1 ; If sel = 1...
m_genesis.kv 292 jmp _mfc0_unknown ; Unknown sel
m_genesis.kv 293 _mfc0_r16_q_0:
m_genesis.kv 294 mov TMP, 0x80008082 ; return 0x80008082
m_genesis.kv 295 jmp _mfc0_writeback ; Done
m_genesis.kv 296 _mfc0_r16_q_1:
m_genesis.kv 297 mov TMP, 0x1e190c8a ; return 0x1e190c8a
m_genesis.kv 298 jmp _mfc0_writeback ; Done
m_genesis.kv 299 ;-----------------------------------------------------------------------------
m_genesis.kv 300 _mfc0_r17: ; 0x11
m_genesis.kv 301 jmp _mfc0_unknown
m_genesis.kv 302 ;-----------------------------------------------------------------------------
m_genesis.kv 303 _mfc0_r18: ; 0x12
m_genesis.kv 304 xor TMP, TMP ; TMP = 0
m_genesis.kv 305 jmp _mfc0_writeback ; Done
m_genesis.kv 306 ;-----------------------------------------------------------------------------
m_genesis.kv 307 _mfc0_r19: ; 0x13
m_genesis.kv 308 xor TMP, TMP ; TMP = 0
m_genesis.kv 309 jmp _mfc0_writeback ; Done
m_genesis.kv 310 ;-----------------------------------------------------------------------------
m_genesis.kv 311 _mfc0_r20: ; 0x14
m_genesis.kv 312 jmp _mfc0_unknown
m_genesis.kv 313 ;-----------------------------------------------------------------------------
m_genesis.kv 314 _mfc0_r21: ; 0x15
m_genesis.kv 315 jmp _mfc0_unknown
m_genesis.kv 316 ;-----------------------------------------------------------------------------
m_genesis.kv 317 _mfc0_r22: ; 0x16
m_genesis.kv 318 jmp _mfc0_unknown
m_genesis.kv 319 ;-----------------------------------------------------------------------------
m_genesis.kv 320 _mfc0_r23: ; 0x17
m_genesis.kv 321 jmp _mfc0_unknown
m_genesis.kv 322 ;-----------------------------------------------------------------------------
m_genesis.kv 323 _mfc0_r24: ; 0x18
m_genesis.kv 324 jmp _mfc0_unknown
m_genesis.kv 325 ;-----------------------------------------------------------------------------
m_genesis.kv 326 _mfc0_r25: ; 0x19
m_genesis.kv 327 jmp _mfc0_unknown
m_genesis.kv 328 ;-----------------------------------------------------------------------------
m_genesis.kv 329 _mfc0_r26: ; 0x1a
m_genesis.kv 330 jmp _mfc0_unknown
m_genesis.kv 331 ;-----------------------------------------------------------------------------
m_genesis.kv 332 _mfc0_r27: ; 0x1b
m_genesis.kv 333 jmp _mfc0_unknown
m_genesis.kv 334 ;-----------------------------------------------------------------------------
m_genesis.kv 335 _mfc0_r28: ; 0x1c
m_genesis.kv 336 jmp _mfc0_unknown
m_genesis.kv 337 ;-----------------------------------------------------------------------------
m_genesis.kv 338 _mfc0_r29: ; 0x1d
m_genesis.kv 339 jmp _mfc0_unknown
m_genesis.kv 340 ;-----------------------------------------------------------------------------
m_genesis.kv 341 _mfc0_r30: ; 0x1e
m_genesis.kv 342 jmp _mfc0_unknown
m_genesis.kv 343 ;-----------------------------------------------------------------------------
m_genesis.kv 344 _mfc0_r31: ; 0x1f
m_genesis.kv 345 jmp _mfc0_unknown
m_genesis.kv 346 ;-----------------------------------------------------------------------------
m_genesis.kv 347 _mfc0_writeback: ; Write result and go to next cycle
m_genesis.kv 348 Wr_Reg rT, TMP ; Regs[rT] := TMP (result)
m_genesis.kv 349 jmp _end_cycle ; Fin
m_genesis.kv 350 ;-----------------------------------------------------------------------------
m_genesis.kv 351 _mfc0_unknown:
m_genesis.kv 352 ; 'The results are UNDEFINED if coprocessor 0 does not contain a
m_genesis.kv 353 ; register as specified by rd and sel.'
m_genesis.kv 354 ACHTUNG "Unknown CP0 Reg Selector in MFC0!" ;; TODO: print detail
m_genesis.kv 355 jmp _end_cycle ; Do nothing, carry on.
m_genesis.kv 356 ;-----------------------------------------------------------------------------
m_genesis.kv 357
m_genesis.kv 358 ;-----------------------------------------------------------------------------
m_genesis.kv 359 ; MTC0 - Move to Coprocessor 0.
m_genesis.kv 360 ; Move the contents of a general register to a coprocessor 0 register.
m_genesis.kv 361 ; The contents of general register rt are loaded into the coprocessor 0
m_genesis.kv 362 ; register specified by the combination of rd and sel (q). Not all
m_genesis.kv 363 ; coprocessor 0 registers support the the sel field. In those instances, the
m_genesis.kv 364 ; sel field must be set to zero.
m_genesis.kv 365 ; Operation: CPR[0, rD, q] = $t
m_genesis.kv 366 ; Syntax: mfc0 $t, $d, q
m_genesis.kv 367 ; Encoding: 0100 0000 100t tttt dddd d000 0000 0qqq
m_genesis.kv 368 ; PRIVILEGED (permitted in Kernel Mode only.)
m_genesis.kv 369 ;-----------------------------------------------------------------------------
m_genesis.kv 370 align GRAIN, db 0x90
m_genesis.kv 371 _m_mtc0:
m_genesis.kv 372 CPType ; Load Q, rD, rT (ecx, eax, ebx)
m_genesis.kv 373 mov rT, R(rT) ; ebx := Regs[rT]
m_genesis.kv 374 JTABLE eax, _MTC0_Table ; Dispatch on rD via MTC0 Table.
m_genesis.kv 375 ;; We continue in _mtc0_rXX where XX is rD.
m_genesis.kv 376 ;-----------------------------------------------------------------------------
m_genesis.kv 377
m_genesis.kv 378 ;-----------------------------------------------------------------------------
m_genesis.kv 379 ; MTC0 Cases. Parameters: Q (ecx), rD (eax), Regs[rT] (ebx)
m_genesis.kv 380 ;-----------------------------------------------------------------------------
m_genesis.kv 381 _mtc0_r00: ; 0x00
m_genesis.kv 382 test ecx, ecx ; Sel != 0 ?
m_genesis.kv 383 jnz _mtc0_unknown ; ... then unknown; else:
m_genesis.kv 384 mov eax, Sr(CP0_Index) ; eax := CP0_Index
m_genesis.kv 385 and ebx, 0xF ; T := T & 0xF
m_genesis.kv 386 and eax, 0x80000000 ; eax := eax & 0x80000000
m_genesis.kv 387 or eax, ebx ; eax := eax | T
m_genesis.kv 388 mov Sr(CP0_Index), eax ; CP0_Index := eax
m_genesis.kv 389 jmp _end_cycle ; Done
m_genesis.kv 390 ;-----------------------------------------------------------------------------
m_genesis.kv 391 _mtc0_r01: ; 0x01
m_genesis.kv 392 jmp _mtc0_unknown
m_genesis.kv 393 ;-----------------------------------------------------------------------------
m_genesis.kv 394 _mtc0_r02: ; 0x02
m_genesis.kv 395 and ebx, 0x3FFFFFF ; T := T & 0x3FFFFFF
m_genesis.kv 396 mov Sr(CP0_EntryLo0), ebx ; CP0_EntryLo0 := T
m_genesis.kv 397 jmp _end_cycle ; Done
m_genesis.kv 398 ;-----------------------------------------------------------------------------
m_genesis.kv 399 _mtc0_r03: ; 0x03
m_genesis.kv 400 and ebx, 0x3FFFFFF ; T := T & 0x3FFFFFF
m_genesis.kv 401 mov Sr(CP0_EntryLo1), ebx ; CP0_EntryLo1 := T
m_genesis.kv 402 jmp _end_cycle ; Done
m_genesis.kv 403 ;-----------------------------------------------------------------------------
m_genesis.kv 404 _mtc0_r04: ; 0x04
m_genesis.kv 405 %define CONTEXTMASK 0xFF800000
m_genesis.kv 406 %define nCONTEXTMASK (0xFFFFFFFF ^ 0xFF800000)
m_genesis.kv 407 mov eax, Sr(CP0_Context) ; eax := CP0_Context
m_genesis.kv 408 and ebx, CONTEXTMASK ; T := T & CONTEXTMASK
m_genesis.kv 409 and eax, nCONTEXTMASK ; eax := eax & ~CONTEXTMASK
m_genesis.kv 410 or eax, ebx ; eax := eax | T
m_genesis.kv 411 mov Sr(CP0_Context), eax ; CP0_Context := eax
m_genesis.kv 412 jmp _end_cycle ; Done
m_genesis.kv 413 ;-----------------------------------------------------------------------------
m_genesis.kv 414 _mtc0_r05: ; 0x05
m_genesis.kv 415 test ecx, ecx ; Sel != 0 ?
m_genesis.kv 416 jnz _mtc0_unknown ; ... then unknown; else:
m_genesis.kv 417 test ebx, ebx ; T != 0 ?
m_genesis.kv 418 jnz _mtc0_r05_untest_pgmask ; If so, eggog
m_genesis.kv 419 and ebx, 0x1FFE000 ; T := T & 0x1FFE000
m_genesis.kv 420 mov Sr(CP0_PageMask), ebx ; CP0_PageMask := T
m_genesis.kv 421 jmp _end_cycle ; Done
m_genesis.kv 422 _mtc0_r05_untest_pgmask: ; Proper kernel won't do this. But if someone does:
m_genesis.kv 423 ACHTUNG "MTC0: Unsupported Page Mask!" ; maybe halt w/ sirens?
m_genesis.kv 424 jmp _end_cycle ; Let's continue (probably wedged...)
m_genesis.kv 425 ;-----------------------------------------------------------------------------
m_genesis.kv 426 _mtc0_r06: ; 0x06
m_genesis.kv 427 test ecx, ecx ; Sel != 0 ?
m_genesis.kv 428 jnz _mtc0_unknown ; ... then unknown; else:
m_genesis.kv 429 and ebx, 0xF ; T := T & 0xF
m_genesis.kv 430 mov Sr(CP0_Wired), ebx ; CP0_Wired := T
m_genesis.kv 431 jmp _end_cycle ; Done
m_genesis.kv 432 ;-----------------------------------------------------------------------------
m_genesis.kv 433 _mtc0_r07: ; 0x07
m_genesis.kv 434 jmp _mtc0_unknown
m_genesis.kv 435 ;-----------------------------------------------------------------------------
m_genesis.kv 436 _mtc0_r08: ; 0x08
m_genesis.kv 437 jmp _mtc0_unknown
m_genesis.kv 438 ;-----------------------------------------------------------------------------
m_genesis.kv 439 _mtc0_r09: ; 0x09
m_genesis.kv 440 test ecx, ecx ; Sel != 0 ?
m_genesis.kv 441 jnz _mtc0_unknown ; ... then unknown; else:
m_genesis.kv 442 mov CP0_Count, ebx ; CP0_Count := T ('fast reg')
m_genesis.kv 443 jmp _end_cycle ; Done
m_genesis.kv 444 ;-----------------------------------------------------------------------------
m_genesis.kv 445 _mtc0_r10: ; 0x0a
m_genesis.kv 446 test ecx, ecx ; Sel != 0 ?
m_genesis.kv 447 jnz _mtc0_unknown ; ... then unknown; else:
m_genesis.kv 448 and ebx, ~0x1F00 ; T := T & ~0x1F00
m_genesis.kv 449 mov Sr(CP0_EntryHi), ebx ; CP0_EntryHi := T
m_genesis.kv 450 jmp _end_cycle ; Done
m_genesis.kv 451 ;-----------------------------------------------------------------------------
m_genesis.kv 452 _mtc0_r11: ; 0x0b
m_genesis.kv 453 test ecx, ecx ; Sel != 0 ?
m_genesis.kv 454 jnz _mtc0_unknown ; ... then unknown; else:
m_genesis.kv 455 ClrIRQ TIMER_IRQ ; Clear MIPS Timer IRQ
m_genesis.kv 456 mov CP0_Compare, ebx ; CP0_Compare := T ('fast reg')
m_genesis.kv 457 jmp _end_cycle ; Done
m_genesis.kv 458 ;-----------------------------------------------------------------------------
m_genesis.kv 459 _mtc0_r12: ; 0x0c
m_genesis.kv 460 test ecx, ecx ; Sel != 0 ?
m_genesis.kv 461 jnz _mtc0_unknown ; ... then unknown; else:
m_genesis.kv 462 %define STATUSMASK 0x7D7CFF17
m_genesis.kv 463 mov eax, CP0_Status ; eax := CP0_Status
m_genesis.kv 464 and ebx, STATUSMASK ; T := T & STATUSMASK
m_genesis.kv 465 and eax, ~STATUSMASK ; eax := eax & ~STATUSMASK
m_genesis.kv 466 or eax, ebx ; eax := eax | T
m_genesis.kv 467 mov CP0_Status, eax ; CP0_Status := eax
m_genesis.kv 468 jmp _end_cycle ; Done
m_genesis.kv 469 ;-----------------------------------------------------------------------------
m_genesis.kv 470 _mtc0_r13: ; 0x0d
m_genesis.kv 471 test ecx, ecx ; Sel != 0 ?
m_genesis.kv 472 jnz _mtc0_unknown ; ... then unknown; else:
errata_slaveirq.kv 473 %define CAUSEMASK ((1 << 23) | (1 << 22) | (255 << 8))
m_genesis.kv 474 mov eax, CP0_Cause ; eax := CP0_Cause
m_genesis.kv 475 and ebx, CAUSEMASK ; T := T & CAUSEMASK
m_genesis.kv 476 and eax, ~CAUSEMASK ; eax := eax & ~CAUSEMASK
m_genesis.kv 477 or eax, ebx ; eax := eax | T
m_genesis.kv 478 mov CP0_Cause, eax ; CP0_Cause := eax
m_genesis.kv 479 jmp _end_cycle ; Done
m_genesis.kv 480 ;-----------------------------------------------------------------------------
m_genesis.kv 481 _mtc0_r14: ; 0x0e
m_genesis.kv 482 test ecx, ecx ; Sel != 0 ?
m_genesis.kv 483 jnz _mtc0_unknown ; ... then unknown; else:
m_genesis.kv 484 mov Sr(CP0_Epc), ebx ; CP0_Epc := T
m_genesis.kv 485 jmp _end_cycle ; Done
m_genesis.kv 486 ;-----------------------------------------------------------------------------
m_genesis.kv 487 _mtc0_r15: ; 0x0f
m_genesis.kv 488 jmp _mtc0_unknown
m_genesis.kv 489 ;-----------------------------------------------------------------------------
m_genesis.kv 490 _mtc0_r16: ; 0x10
m_genesis.kv 491 jmp _end_cycle ; Done
m_genesis.kv 492 ;-----------------------------------------------------------------------------
m_genesis.kv 493 _mtc0_r17: ; 0x11
m_genesis.kv 494 jmp _mtc0_unknown
m_genesis.kv 495 ;-----------------------------------------------------------------------------
m_genesis.kv 496 _mtc0_r18: ; 0x12
m_genesis.kv 497 jmp _end_cycle ; Done
m_genesis.kv 498 ;-----------------------------------------------------------------------------
m_genesis.kv 499 _mtc0_r19: ; 0x13
m_genesis.kv 500 jmp _end_cycle ; Done
m_genesis.kv 501 ;-----------------------------------------------------------------------------
m_genesis.kv 502 _mtc0_r20: ; 0x14
m_genesis.kv 503 jmp _mtc0_unknown ; Done
m_genesis.kv 504 ;-----------------------------------------------------------------------------
m_genesis.kv 505 _mtc0_r21: ; 0x15
m_genesis.kv 506 jmp _mtc0_unknown ; Done
m_genesis.kv 507 ;-----------------------------------------------------------------------------
m_genesis.kv 508 _mtc0_r22: ; 0x16
m_genesis.kv 509 jmp _mtc0_unknown ; Done
m_genesis.kv 510 ;-----------------------------------------------------------------------------
m_genesis.kv 511 _mtc0_r23: ; 0x17
m_genesis.kv 512 jmp _mtc0_unknown ; Done
m_genesis.kv 513 ;-----------------------------------------------------------------------------
m_genesis.kv 514 _mtc0_r24: ; 0x18
m_genesis.kv 515 jmp _mtc0_unknown ; Done
m_genesis.kv 516 ;-----------------------------------------------------------------------------
m_genesis.kv 517 _mtc0_r25: ; 0x19
m_genesis.kv 518 jmp _mtc0_unknown ; Done
m_genesis.kv 519 ;-----------------------------------------------------------------------------
m_genesis.kv 520 _mtc0_r26: ; 0x1a
m_genesis.kv 521 jmp _mtc0_unknown ; Done
m_genesis.kv 522 ;-----------------------------------------------------------------------------
m_genesis.kv 523 _mtc0_r27: ; 0x1b
m_genesis.kv 524 jmp _mtc0_unknown ; Done
m_genesis.kv 525 ;-----------------------------------------------------------------------------
m_genesis.kv 526 _mtc0_r28: ; 0x1c
m_genesis.kv 527 jmp _mtc0_unknown ; Done
m_genesis.kv 528 ;-----------------------------------------------------------------------------
m_genesis.kv 529 _mtc0_r29: ; 0x1d
m_genesis.kv 530 jmp _mtc0_unknown ; Done
m_genesis.kv 531 ;-----------------------------------------------------------------------------
m_genesis.kv 532 _mtc0_r30: ; 0x1e
m_genesis.kv 533 jmp _mtc0_unknown ; Done
m_genesis.kv 534 ;-----------------------------------------------------------------------------
m_genesis.kv 535 _mtc0_r31: ; 0x1f
m_genesis.kv 536 jmp _mtc0_unknown ; Done
m_genesis.kv 537 ;-----------------------------------------------------------------------------
m_genesis.kv 538 _mtc0_unknown:
m_genesis.kv 539 ; 'The results are UNDEFINED if coprocessor 0 does not contain a
m_genesis.kv 540 ; register as specified by rd and sel.'
m_genesis.kv 541 ACHTUNG "Unknown CP0 Reg Selector in MTC0!" ;; TODO: print detail
m_genesis.kv 542 jmp _end_cycle ; Done
m_genesis.kv 543 ;-----------------------------------------------------------------------------
m_genesis.kv 544
m_genesis.kv 545 ;-----------------------------------------------------------------------------
m_genesis.kv 546 ; WAIT - Enter Standby Mode.
m_genesis.kv 547 ; Wait for Event.
m_genesis.kv 548 ; Puts the emulator into 'wait' mode.
m_genesis.kv 549 ; Encoding: 0100 001- ---- ---- ---- ---- --10 0000
m_genesis.kv 550 ; PRIVILEGED (permitted in Kernel Mode only.)
m_genesis.kv 551 ;-----------------------------------------------------------------------------
m_genesis.kv 552 align GRAIN, db 0x90
m_genesis.kv 553 _m_wait:
m_genesis.kv 554 ; no fields
m_genesis.kv 555 Flg_On Waiting ; Set 'Waiting' Flag.
m_genesis.kv 556 jmp _end_cycle
m_genesis.kv 557 ;-----------------------------------------------------------------------------