- 6AD0018398EFC679130DB6E4ABDF4082D644BCBB623CE66C49899053B0A032A27FF1DE0702EFECD0A5BF6718ADFBDF9F1C38B7E2F1EFAE34CFAF0258E0731F8D
+ 016C026DBE4230BD120C0FC4269E61BD8A44B82580289EFC90FED0792B5893A5727E069191FBFB0E32C3C40D2700B4A39A5ACB0BE1FDBFC475274C344368626A
m/ram.asm
(85 . 44)(85 . 40)
418 ;-----------------------------------------------------------------------------
419
420 ;-----------------------------------------------------------------------------
421 ; Translate_Address : virtual address in eax; output (physical addr) in eax
422 ; Mark both Read and Write TLB Caches as blown:
423 ;-----------------------------------------------------------------------------
424 %macro Invalidate_TLB_Cache 0
425 and Flag_Reg, ~((1 << TLB_Rd_Cache_Valid) | (1 << TLB_Wr_Cache_Valid))
426 %endmacro
427 ;-----------------------------------------------------------------------------
428
429 ;-----------------------------------------------------------------------------
430 ; Virt2Phys Read : virtual address in eax; output (physical addr) in eax
431 ;-----------------------------------------------------------------------------
432 align GRAIN, db 0x90
433 _Virt_To_Phys:
434 _Virt_To_Phys_Read:
435 bt eax, 31 ; CF := 31st (top) bit of vAddr
436 jc _Above_7FFFFFFF ; If 31st bit = 1, kseg 0/1/2; else:
437 jc .Above_7FFFFFFF ; If 31st bit = 1, kseg 0/1/2; else:
438 ;; 0x00000000 <= vAddr <= 0x7FFFFFFF (kuseg) :
439 bt CP0_Status, CP0St_ERL ; CF := CP0St_ERL Flag
440 jnc _TLB_Lookup ; If ERL = 0: TLB Lookup required; else:
441 jmp _No_Tlb_Lookup ; pAddr is equal to vAddr, return.
442 _Above_7FFFFFFF:
443 jnc .TLB_Lookup ; If ERL = 0: TLB Lookup required; else:
444 ret ; pAddr is equal to vAddr, return.
445 .Above_7FFFFFFF:
446 bt eax, 30 ; CF := 30th (2nd from top) bt of vAddr
447 jc _Above_BFFFFFFF ; If 30th bit = 1 : kseg2; else:
448 jc .Above_BFFFFFFF ; If 30th bit = 1 : kseg2; else:
449 ;; 0x80000000 <= vAddr <= 0x9FFFFFFF (kseg0) :
450 ;; 0xA0000000 <= vAddr <= 0xBFFFFFFF (kseg1) :
451 and eax, 0x1FFFFFFF ; kseg0 and kseg1: clear top 3 bits,
452 jmp _No_Tlb_Lookup ; i.e. pAddr := bottom 29 bts of vAddr.
453 _Above_BFFFFFFF: ;; 0xC0000000 <= vAddr <= 0xFFFFFFFF (kseg2) :
454 bt CP0_Status, CP0St_UM ; CF := CP0St_UM Flag
455 jnc _TLB_Lookup ; If UM = 0: K. Mode, so do TLB; else:
456 test CP0_Status, (1 << CP0St_EXL) | (1 << CP0St_ERL) ; EXL or ERL
457 jnz _TLB_Lookup ; If EXL && ERL, K. Mode, do TLB
458 ret ; i.e. pAddr := bottom 29 bts of vAddr.
459 .Above_BFFFFFFF: ;; 0xC0000000 <= vAddr <= 0xFFFFFFFF (kseg2) :
460 JMP_IF_KERNELMODE .TLB_Lookup ; If Kernel Mode, do TLB lookup;
461 ;; Else: vAddr is in kseg2, but we are NOT in Kernel Mode:
462 Flg_Get IsWriting ; Is Writing?
463 jc _V2P_Eggog_Wr ; If so, we want to set AdES;
464 _V2P_Eggog_Rd: ; ... otherwise, set AdEL.
465 SetEXC EXC_AdEL ; Fetch address error.
466 jmp _V2P_Eggog_Fin ; Proceed to abort.
467 _V2P_Eggog_Wr:
468 SetEXC EXC_AdES ; Store address error.
469 _V2P_Eggog_Fin:
470 ;; Will go into exception handler instead of back to _Virt_xxx etc
471 add rsp, 16 ; squelch return to _Virt_xxx and its caller
472 push _Handle_Exception ; 'return' directly to exc handler.
473 _No_Tlb_Lookup:
474 Flg_Off IsWriting ; Consume 'is writing' flag.
475 push _Handle_Exception_Other ; 'return' directly to exc handler.
476 ret ; Done.
477 _TLB_Lookup: ; TLB Lookup Required:
478 .TLB_Lookup: ; TLB Lookup Required:
479 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
480 ;; Save ebx, ecx, edx, AUX, to xmm ;;
481 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(131 . 71)(127 . 235)
483 movd xmm2, edx
484 movd xmm3, AUX
485 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
486 Flg_Off ExcWasTLBNoMatch ; Clear the ExcWasTLBNoMatch Flag
487 mov ecx, eax ; ecx := eax (vAddr)
488 and ecx, 0xFFFFF000 ; ecx := ecx & 0xFFFFF000
489 shr ecx, 13 ; ecx := ecx >> 13 (get vAddr's Tag)
490 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
491 ;; Find out whether we actually must do the lookup, or can use cached:
492 Flg_Get TLB_Rd_Cache_Valid ; Is Read TLB Cache valid?
493 jnc .Lookup_Must ; If Read TLB Cache invalid -- must!
494 bt eax, 12 ; Test odd/even junior bit
495 jc .Rd_Cached_Odd ; If odd, look at last Odd vAddr Tag
496 .Rd_Cached_Even: ; If even, look at last Even vAddr Tag
497 movd edx, Rd_E_Last_Tag ; edx := last Even vAddr's Tag
498 cmp ecx, edx ; is the current vAddr's Tag equal?
499 jne .Lookup_Must ; ... if not, must do the lookup dance;
500 ;; ... Otherwise, we have an Even cache hit:
501 movd ebx, Rd_E_Last_PFN ; ebx := last good Even PFN
502 jmp .Cache_Hit ; apply the PFN and wrap up.
503 .Rd_Cached_Odd:
504 movd edx, Rd_O_Last_Tag ; edx := last Odd vAddr's Tag
505 cmp ecx, edx ; is the current vAddr's Tag equal?
506 jne .Lookup_Must ; ... if not, must do the lookup dance;
507 ;; ... Otherwise, we have an Odd cache hit:
508 movd ebx, Rd_O_Last_PFN ; ebx := last good Odd PFN
509 jmp .Cache_Hit ; apply the PFN and wrap up.
510 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
511 ;; Failing the above, we must actually walk the TLB:
512 .Lookup_Must:
513 movd xmm4, ecx ; xmm4 := current vAddr's Tag
514 ;; Get the active ASID:
515 mov edx, Sr(CP0_EntryHi) ; edx := CP0_EntryHi
516 and edx, 0xFF ; edx := edx & 0xFF (get current ASID)
517 ;; For each slot in table (0 .. 15), attempt lookup
518 xor AUX, AUX ; Start with the 0-th entry in table
519 _Lookup_TLB_E:
520 mov ecx, eax ; ecx := eax (vAddr)
521 and ecx, 0xFFFFF000 ; ecx := ecx & 0xFFFFF000
522 shr ecx, 13 ; ecx := ecx >> 13 (get vAddr's Tag)
523 .Lookup_TLB_E:
524 movd ecx, xmm4 ; ecx := current vAddr's Tag
525 mov ebx, TLB_E(AUX) ; ebx := current TLB entry
526 and ebx, TLB_VPN2_Mask ; get VPN2 of this entry
527 cmp ebx, ecx ; cmp(entry.VPN2, vAddr.tag)
528 jne _Lookup_TLB_E_Not_Here ; if entry.VPN2 != vAddr.tag: no match
529 jne .Lookup_TLB_E_Not_Here ; if entry.VPN2 != vAddr.tag: no match
530 mov ebx, TLB_E(AUX) ; ebx := current TLB entry
531 bt ebx, TLB_G ; is entry.G = 1?
532 jc _Lookup_TLB_E_Match ; then match.
533 jc .Lookup_TLB_E_Match ; then match.
534 shr ebx, TLB_ASID_Shift ; ebx := ebx >> TLB_ASID_Shift
535 and ebx, TLB_ASID_Mask ; ebx := entry.ASID
536 cmp ebx, edx ; entry.ASID = current ASID ?
537 jne _Lookup_TLB_E_Not_Here ; if neither G=1 nor ASID match.
538 jne .Lookup_TLB_E_Not_Here ; if neither G=1 nor ASID match.
539 mov ebx, TLB_E(AUX) ; ebx := current TLB entry
540 _Lookup_TLB_E_Match: ; TLB Match:
541 .Lookup_TLB_E_Match: ; TLB Match:
542 bt eax, 12 ; Test odd/even junior bit
543 jc _Lookup_TLB_E_Match_Odd ; If odd: test V1, D1
544 _Lookup_TLB_E_Match_Even: ; If even: test V0, D0
545 jc .Lookup_TLB_E_Match_Odd ; If odd: test V1, D1
546 .Lookup_TLB_E_Match_Even: ; If even: test V0, D0
547 bt ebx, TLB_V0 ; Is entry.V0=1 ?
548 jnc .Lookup_TLB_E_Invalid ; If not, TLBRET_INVALID
549 lea ecx, TLB_PFN_E(AUX) ; prepare to load even PFN entry
550 mov ebx, dword [ecx] ; Actually load the current PFN entry
551 movd Rd_E_Last_PFN, ebx ; Save the current PFN as last Even
552 movd ecx, xmm4 ; ecx := the current Tag
553 movd Rd_E_Last_Tag, ecx ; Save the current Tag as last Even
554 jmp .Lookup_TLB_E_Match_Yes ; Since we're reading: go to Match Yes
555 .Lookup_TLB_E_Match_Odd: ; Odd bit:
556 bt ebx, TLB_V1 ; Is entry.V1=1 ?
557 jnc .Lookup_TLB_E_Invalid ; If not, TLBRET_INVALID
558 lea ecx, TLB_PFN_O(AUX) ; prepare to load odd PFN entry
559 mov ebx, dword [ecx] ; Actually load the current PFN entry
560 movd Rd_O_Last_PFN, ebx ; Save the current PFN as last Odd
561 movd ecx, xmm4 ; ecx := the current Tag
562 movd Rd_O_Last_Tag, ecx ; Save the current Tag as last Odd
563 .Lookup_TLB_E_Match_Yes: ; This is the 'success' case
564 Flg_On TLB_Rd_Cache_Valid
565 ; Upon next TLB lookup, if cache is valid, and Tag remains same
566 ; as before, we can use the same PFN as was obtained last time
567 ; for the respective 12th bit arity of the vAddr!
568 .Cache_Hit:
569 and eax, 0xFFF ; vAddr := vAddr & 0xFFF
570 or eax, ebx ; vAddr := vAddr | entry.PFN[lowbit]
571 jmp _Lookup_TLB_Done ; vAddr is now correct pAddr, done.
572 .Lookup_TLB_E_Not_Here: ; try next one in the table, if any
573 inc AUX ; index := index + 1
574 cmp AUX, TLB_ENTRIES_COUNT ; see if still in range 0 .. n-1
575 jb .Lookup_TLB_E ; if in range, go to next entry
576 ;; ... else:
577 add rsp, 16 ; squelch return to _Virt_xxx and its caller
578 push _Handle_Exception_TLB_NoMatch ; 'return' straight to handler.
579 jmp _Lookup_TLB_E_WriteExtr ; Wrap up
580 .Lookup_TLB_E_Invalid:
581 SetEXC EXC_TLBL ; Set the EXC_TLBL Exception
582 add rsp, 16 ; squelch return to _Virt_xxx and its caller
583 push _Handle_Exception_Other ; 'return' straight to handler.
584 jmp _Lookup_TLB_E_WriteExtr ; Go to the common epilogue.
585 ;-----------------------------------------------------------------------------
586
587 ;-----------------------------------------------------------------------------
588 ; Virt2Phys Write : virtual address in eax; output (physical addr) in eax
589 ;-----------------------------------------------------------------------------
590 align GRAIN, db 0x90
591 _Virt_To_Phys_Write:
592 bt eax, 31 ; CF := 31st (top) bit of vAddr
593 jc .Above_7FFFFFFF ; If 31st bit = 1, kseg 0/1/2; else:
594 ;; 0x00000000 <= vAddr <= 0x7FFFFFFF (kuseg) :
595 bt CP0_Status, CP0St_ERL ; CF := CP0St_ERL Flag
596 jnc .TLB_Lookup ; If ERL = 0: TLB Lookup required; else:
597 ret ; pAddr is equal to vAddr, return.
598 .Above_7FFFFFFF:
599 bt eax, 30 ; CF := 30th (2nd from top) bt of vAddr
600 jc .Above_BFFFFFFF ; If 30th bit = 1 : kseg2; else:
601 ;; 0x80000000 <= vAddr <= 0x9FFFFFFF (kseg0) :
602 ;; 0xA0000000 <= vAddr <= 0xBFFFFFFF (kseg1) :
603 and eax, 0x1FFFFFFF ; kseg0 and kseg1: clear top 3 bits,
604 ret ; i.e. pAddr := bottom 29 bts of vAddr.
605 .Above_BFFFFFFF: ;; 0xC0000000 <= vAddr <= 0xFFFFFFFF (kseg2) :
606 JMP_IF_KERNELMODE .TLB_Lookup ; If Kernel Mode, do TLB lookup;
607 ;; Else: vAddr is in kseg2, but we are NOT in Kernel Mode:
608 SetEXC EXC_AdES ; Store address error.
609 ;; Will go into exception handler instead of back to _Virt_xxx etc
610 add rsp, 16 ; squelch return to _Virt_xxx and its caller
611 push _Handle_Exception_Other ; 'return' directly to exc handler.
612 ret ; Done.
613 .TLB_Lookup: ; TLB Lookup Required:
614 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
615 ;; Save ebx, ecx, edx, AUX, to xmm ;;
616 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
617 movd xmm0, ebx
618 movd xmm1, ecx
619 movd xmm2, edx
620 movd xmm3, AUX
621 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
622 mov ecx, eax ; ecx := eax (vAddr)
623 and ecx, 0xFFFFF000 ; ecx := ecx & 0xFFFFF000
624 shr ecx, 13 ; ecx := ecx >> 13 (get vAddr's Tag)
625 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
626 ;; Find out whether we actually must do the lookup, or can use cached:
627 Flg_Get TLB_Wr_Cache_Valid ; Is Write TLB Cache valid?
628 jnc .Lookup_Must ; If Write TLB Cache invalid -- must!
629 bt eax, 12 ; Test odd/even junior bit
630 jc .Wr_Cached_Odd ; If odd, look at last Odd vAddr Tag
631 .Wr_Cached_Even: ; If even, look at last Even vAddr Tag
632 movd edx, Wr_E_Last_Tag ; edx := last Even vAddr's Tag
633 cmp ecx, edx ; is the current vAddr's Tag equal?
634 jne .Lookup_Must ; ... if not, must do the lookup dance;
635 ;; ... Otherwise, we have an Even cache hit:
636 movd ebx, Wr_E_Last_PFN ; ebx := last good Even PFN
637 jmp .Cache_Hit ; apply the PFN and wrap up.
638 .Wr_Cached_Odd:
639 movd edx, Wr_O_Last_Tag ; edx := last Odd vAddr's Tag
640 cmp ecx, edx ; is the current vAddr's Tag equal?
641 jne .Lookup_Must ; ... if not, must do the lookup dance;
642 ;; ... Otherwise, we have an Odd cache hit:
643 movd ebx, Wr_O_Last_PFN ; ebx := last good Odd PFN
644 jmp .Cache_Hit ; apply the PFN and wrap up.
645 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
646 ;; Failing the above, we must actually walk the TLB:
647 .Lookup_Must:
648 movd xmm4, ecx ; xmm4 := current vAddr's Tag
649 ;; Get the active ASID:
650 mov edx, Sr(CP0_EntryHi) ; edx := CP0_EntryHi
651 and edx, 0xFF ; edx := edx & 0xFF (get current ASID)
652 ;; For each slot in table (0 .. 15), attempt lookup
653 xor AUX, AUX ; Start with the 0-th entry in table
654 .Lookup_TLB_E:
655 movd ecx, xmm4 ; ecx := current vAddr's Tag
656 mov ebx, TLB_E(AUX) ; ebx := current TLB entry
657 and ebx, TLB_VPN2_Mask ; get VPN2 of this entry
658 cmp ebx, ecx ; cmp(entry.VPN2, vAddr.tag)
659 jne .Lookup_TLB_E_Not_Here ; if entry.VPN2 != vAddr.tag: no match
660 mov ebx, TLB_E(AUX) ; ebx := current TLB entry
661 bt ebx, TLB_G ; is entry.G = 1?
662 jc .Lookup_TLB_E_Match ; then match.
663 shr ebx, TLB_ASID_Shift ; ebx := ebx >> TLB_ASID_Shift
664 and ebx, TLB_ASID_Mask ; ebx := entry.ASID
665 cmp ebx, edx ; entry.ASID = current ASID ?
666 jne .Lookup_TLB_E_Not_Here ; if neither G=1 nor ASID match.
667 mov ebx, TLB_E(AUX) ; ebx := current TLB entry
668 .Lookup_TLB_E_Match: ; TLB Match:
669 bt eax, 12 ; Test odd/even junior bit
670 jc .Lookup_TLB_E_Match_Odd ; If odd: test V1, D1
671 .Lookup_TLB_E_Match_Even: ; If even: test V0, D0
672 bt ebx, TLB_V0 ; Is entry.V0=1 ?
673 jnc _Lookup_TLB_E_Invalid ; If not, TLBRET_INVALID
674 jnc .Lookup_TLB_E_Invalid ; If not, TLBRET_INVALID
675 bt ebx, TLB_D0 ; Is entry.D0=1 ?
676 jc _Lookup_TLB_E_Match_Yes ; If entry.D0=1, then Match Yes
677 jmp _Lookup_TLB_E_Match_Wr ; else, go to 'is writing?'
678 _Lookup_TLB_E_Match_Odd: ; Odd bit:
679 lea ecx, TLB_PFN_O(AUX) ; prepare to load odd PFN entry
680 jnc .Lookup_TLB_E_Dirty ; If not, go to 'Dirty'
681 ;; Not invalid or dirty:
682 lea ecx, TLB_PFN_E(AUX) ; prepare to load even PFN entry
683 mov ebx, dword [ecx] ; Actually load the current PFN entry
684 movd Wr_E_Last_PFN, ebx ; Save the current PFN as last Even
685 movd ecx, xmm4 ; ecx := the current Tag
686 movd Wr_E_Last_Tag, ecx ; Save the current Tag as last Even
687 jmp .Lookup_TLB_E_Match_Yes ; ;; Proceed to 'match' :
688 .Lookup_TLB_E_Match_Odd: ; Odd bit:
689 bt ebx, TLB_V1 ; Is entry.V1=1 ?
690 jnc _Lookup_TLB_E_Invalid ; If not, TLBRET_INVALID
691 jnc .Lookup_TLB_E_Invalid ; If not, TLBRET_INVALID
692 bt ebx, TLB_D1 ; Is entry.D1=1 ?
693 jc _Lookup_TLB_E_Match_Yes ; If entry.D1=1, then Match Yes
694 _Lookup_TLB_E_Match_Wr:
695 Flg_Get IsWriting ; Is Writing?
696 jnc _Lookup_TLB_E_Match_Yes ; If not writing, go to Match Yes
697 _Lookup_TLB_E_Dirty: ; ... else, Dirty:
698 SetEXC EXC_Mod ; Set the EXC_Mod Exception
699 jmp _Lookup_TLB_E_WriteExtr ; Write the 'extra data' and finish.
700 _Lookup_TLB_E_Match_Yes: ; This is the 'success' case
701 jnc .Lookup_TLB_E_Dirty ; If not, go to 'Dirty'
702 ;; Not invalid or dirty:
703 lea ecx, TLB_PFN_O(AUX) ; prepare to load odd PFN entry
704 mov ebx, dword [ecx] ; Actually load the current PFN entry
705 movd Wr_O_Last_PFN, ebx ; Save the current PFN as last Odd
706 movd ecx, xmm4 ; ecx := the current Tag
707 movd Wr_O_Last_Tag, ecx ; Save the current Tag as last Odd
708 ;; Proceed to 'match' :
709 .Lookup_TLB_E_Match_Yes: ; This is the 'success' case
710 Flg_On TLB_Wr_Cache_Valid
711 ; Upon next TLB lookup, if cache is valid, and Tag remains same
712 ; as before, we can use the same PFN as was obtained last time
713 ; for the respective 12th bit arity of the vAddr!
714 .Cache_Hit:
715 and eax, 0xFFF ; vAddr := vAddr & 0xFFF
716 or eax, ebx ; vAddr := vAddr | entry.PFN[lowbit]
717 jmp _Lookup_TLB_Done ; vAddr is now correct pAddr, done.
718 _Lookup_TLB_E_Not_Here: ; try next one in the table, if any
719 .Lookup_TLB_E_Not_Here: ; try next one in the table, if any
720 inc AUX ; index := index + 1
721 cmp AUX, TLB_ENTRIES_COUNT ; see if still in range 0 .. n-1
722 jb _Lookup_TLB_E ; if in range, go to next entry
723 jb .Lookup_TLB_E ; if in range, go to next entry
724 ;; ... else:
725 Flg_On ExcWasTLBNoMatch ; Set the ExcWasTLBNoMatch Flag
726 ;; ... now drop down into 'invalid' :
727 _Lookup_TLB_E_Invalid:
728 Flg_Get IsWriting ; Was Writing?
729 jc _Lookup_TLB_E_Invalid_W ; If so, we want to set EXC_TLBS
730 _Lookup_TLB_E_Invalid_R: ; Otherwise, set EXC_TLBL exception
731 SetEXC EXC_TLBL ; Set the EXC_TLBL Exception
732 add rsp, 16 ; squelch return to _Virt_xxx and its caller
733 push _Handle_Exception_TLB_NoMatch ; 'return' straight to handler.
734 jmp _Lookup_TLB_E_WriteExtr ; Wrap up
735 .Lookup_TLB_E_Dirty: ; ... else, Dirty:
736 SetEXC EXC_Mod ; Set the EXC_Mod Exception
737 add rsp, 16 ; squelch return to _Virt_xxx and its caller
738 push _Handle_Exception_Other ; 'return' straight to handler.
739 jmp _Lookup_TLB_E_WriteExtr ; Write the 'extra data' and finish.
740 _Lookup_TLB_E_Invalid_W:
741 .Lookup_TLB_E_Invalid: ; Invalid Write:
742 SetEXC EXC_TLBS ; Set the EXC_TLBS Exception
743 ;; then drop down to 'write extra' :
744 add rsp, 16 ; squelch return to _Virt_xxx and its caller
745 push _Handle_Exception_Other ; 'return' straight to handler.
746 ;; then drop down to _Lookup_TLB_E_WriteExtr
747
748 ;-----------------------------------------------------------------------------
749 ; Epilogue common to _Virt_To_Phys_Read and _Virt_To_Phys_Write:
750 ;-----------------------------------------------------------------------------
751 _Lookup_TLB_E_WriteExtr: ; Write the 'extra data' and finish
752 mov Sr(CP0_BadVAddr), eax ; CP0_BadVAddr := vAddr
753 mov ecx, eax ; ecx := vAddr
(210 . 13)(370 . 15)
755 and ebx, 0xFF ; ebx := ebx & 0xFF
756 and ecx, 0xFFFFE000 ; ecx := ecx & 0xFFFFE000
757 or ebx, ecx ; ebx := ebx | ecx
758 cmp ebx, Sr(CP0_EntryHi) ; Find whether changing CP0_EntryHi
759 je .Not_Changed_EntryHi ; ... if not, skip;
760 .Changed_EntryHi: ; If we are changing CP0_EntryHi:
761 Invalidate_TLB_Cache ; Invalidate both R and W TLB Caches
762 mov Sr(CP0_EntryHi), ebx ; CP0_EntryHi := ebx
763 .Not_Changed_EntryHi:
764 ;; Will go into exception handler instead of back to _Virt_xxx etc
765 add rsp, 16 ; squelch return to _Virt_xxx and its caller
766 push _Handle_Exception ; 'return' directly to exc handler.
767 ;; and drop into 'done' :
768 _Lookup_TLB_Done:
769 Flg_Off IsWriting ; Consume 'is writing' flag.
770 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
771 ;; Restore ebx, ecx, edx, AUX, from xmm ;;
772 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(234 . 7)(396 . 7)
774 ; 2) would go faster if used tmp instead of self-clobbering rax ?
775 align GRAIN, db 0x90
776 _Virt_Read_Word:
777 call _Virt_To_Phys ; Transform vAddr to pAddr
778 call _Virt_To_Phys_Read ; Transform vAddr to pAddr (for Read)
779 test eax, 0x3 ; Are any of the bottom 2 bits set?
780 jnz _V_Rd_Word_Unaligned ; If yes, go to eggog. Else:
781 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(256 . 7)(418 . 7)
783 SetEXC EXC_AdEL ; Fetch address error.
784 ;; Will go into exception handler instead of back to caller
785 add rsp, 8 ; squelch return to original caller
786 push _Handle_Exception ; 'return' directly to exc handler.
787 push _Handle_Exception_Other ; 'return' directly to exc handler.
788 ret ; Go there.
789 ;-----------------------------------------------------------------------------
790
(268 . 8)(430 . 7)
792 ; 3) do we need to explicitly zero-extend rax here?
793 align GRAIN, db 0x90
794 _Virt_Write_Word:
795 Flg_On IsWriting ; Tell the translator that we're writing
796 call _Virt_To_Phys ; Transform vAddr to pAddr
797 call _Virt_To_Phys_Write ; Transform vAddr to pAddr (for Write)
798 test eax, 0x3 ; Are any of the bottom 2 bits set?
799 jnz _V_Wr_Word_Unaligned ; If yes, go to eggog. Else:
800 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(291 . 7)(452 . 7)
802 SetEXC EXC_AdES ; Store address error.
803 ;; Will go into exception handler instead of back to caller
804 add rsp, 8 ; squelch return to original caller
805 push _Handle_Exception ; 'return' directly to exc handler.
806 push _Handle_Exception_Other ; 'return' directly to exc handler.
807 ret ; Go there.
808 ;-----------------------------------------------------------------------------
809
(300 . 7)(461 . 7)
811 ;-----------------------------------------------------------------------------
812 align GRAIN, db 0x90
813 _Virt_Read_Byte:
814 call _Virt_To_Phys ; Transform vAddr to pAddr
815 call _Virt_To_Phys_Read ; Transform vAddr to pAddr (for Read)
816 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
817 ;; If pAddr is in Memory-Mapped Device space:
818 JMP_If_In eax, MMIO_BASE, MMIO_TOP, _Phys_Device_Read_Byte
(324 . 7)(485 . 7)
820 SetEXC EXC_AdEL ; Fetch address error.
821 ;; Will go into exception handler instead of back to caller
822 add rsp, 8 ; squelch return to original caller
823 push _Handle_Exception ; 'return' directly to exc handler.
824 push _Handle_Exception_Other ; 'return' directly to exc handler.
825 ret ; Go there.
826 ;-----------------------------------------------------------------------------
827
(333 . 8)(494 . 7)
829 ;-----------------------------------------------------------------------------
830 align GRAIN, db 0x90
831 _Virt_Write_Byte:
832 Flg_On IsWriting ; Tell the translator that we're writing
833 call _Virt_To_Phys ; Transform vAddr to pAddr
834 call _Virt_To_Phys_Write ; Transform vAddr to pAddr (for Write)
835 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
836 ;; If pAddr is in Memory-Mapped Device space:
837 JMP_If_In eax, MMIO_BASE, MMIO_TOP, _Phys_Device_Write_Byte
(357 . 7)(517 . 7)
839 SetEXC EXC_AdES ; Store address error.
840 ;; Will go into exception handler instead of back to caller
841 add rsp, 8 ; squelch return to original caller
842 push _Handle_Exception ; 'return' directly to exc handler.
843 push _Handle_Exception_Other ; 'return' directly to exc handler.
844 ret ; Go there.
845 ;-----------------------------------------------------------------------------
846
(416 . 5)(576 . 6)
848 ;; Store PFN:
849 mov TLB_PFN_E(AUX), edx ; Store PFN0
850 mov TLB_PFN_O(AUX), ebx ; Store PFN1
851 Invalidate_TLB_Cache ; Invalidate both R and W TLB Caches
852 ret ; Done.
853 ;-----------------------------------------------------------------------------