-
+ 6AD0018398EFC679130DB6E4ABDF4082D644BCBB623CE66C49899053B0A032A27FF1DE0702EFECD0A5BF6718ADFBDF9F1C38B7E2F1EFAE34CFAF0258E0731F8D
m/ram.asm
(0 . 0)(1 . 420)
5128 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5129 ;; ;;
5130 ;; This file is part of 'M', a MIPS system emulator. ;;
5131 ;; ;;
5132 ;; (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) ;;
5133 ;; http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html ;;
5134 ;; ;;
5135 ;; You do not have, nor can you ever acquire the right to use, copy or ;;
5136 ;; distribute this software ; Should you use this software for any purpose, ;;
5137 ;; or copy and distribute it to anyone or in any manner, you are breaking ;;
5138 ;; the laws of whatever soi-disant jurisdiction, and you promise to ;;
5139 ;; continue doing so for the indefinite future. In any case, please ;;
5140 ;; always : read and understand any software ; verify any PGP signatures ;;
5141 ;; that you use - for any purpose. ;;
5142 ;; ;;
5143 ;; See also http://trilema.com/2015/a-new-software-licensing-paradigm . ;;
5144 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5145
5146 ;-----------------------------------------------------------------------------
5147 ;; State
5148 ;-----------------------------------------------------------------------------
5149 section .bss
5150 M resb 8 ; Addr mmap'd M (message) buffer
5151 Mbytes resb 8 ; Length of image (bytes)
5152 RAMbytes resb 8 ; Total size of RAM (bytes)
5153 ;-----------------------------------------------------------------------------
5154
5155 section .text
5156
5157 ;-----------------------------------------------------------------------------
5158 ; Jump if register value resides in given range
5159 ;-----------------------------------------------------------------------------
5160 %macro JMP_If_In 4 ; %1: register, %2: r.bottom, %3: r.top, %4: dest.
5161 cmp %1, %3 ; Compare register to TOP of range
5162 ja %%nope ; If above top -- skip.
5163 cmp %1, %2 ; Compare register to BOTTOM of range
5164 jb %%nope ; If below bottom -- skip.
5165 jmp %4 ; ... Else, register is in the range, and jump.
5166 %%nope
5167 %endmacro
5168 ;-----------------------------------------------------------------------------
5169
5170 ;-----------------------------------------------------------------------------
5171 ; Allocate RAM:
5172 ;-----------------------------------------------------------------------------
5173 _ram_allocate:
5174 ;; Allocate memory for sim RAM:
5175 mov rax, SYS_MMAP
5176 xor r9, r9 ; offset=0
5177 xor r8, r8
5178 mov r10, MAP_PRIVATE | MAP_ANONYMOUS
5179 mov rdx, PROT_READ | PROT_WRITE
5180 mov rsi, [RAMbytes] ; # of bytes to allocate
5181 xor rdi, rdi ; os will give addr
5182 syscall ; invoke mmap
5183 ;; Verify whether we actually got our memory:
5184 cmp rax, 0
5185 jg _mmap_ok
5186 ;; ... if not:
5187 EGGOG "Could not allocate memory for sim RAM!"
5188 _mmap_ok: ;; we got the memory;
5189 ret
5190 ;-----------------------------------------------------------------------------
5191
5192 ;-----------------------------------------------------------------------------
5193 ; Free RAM:
5194 ;-----------------------------------------------------------------------------
5195 _ram_deallocate:
5196 mov rax, SYS_MUNMAP
5197 mov rsi, [RAMbytes]
5198 mov rdi, [M]
5199 syscall ; munmap(M, Mbytes)
5200 ret
5201 ;-----------------------------------------------------------------------------
5202
5203 ;-----------------------------------------------------------------------------
5204 ; Init RAM:
5205 ;-----------------------------------------------------------------------------
5206 _ram_init:
5207 mov RAM_Floor, [M] ; Set 'floor' of RAM
5208 mov RAM_Ceiling, RAM_Floor ; 'ceiling'
5209 add RAM_Ceiling, [RAMbytes]; ... size of the mmap
5210 ;; TODO: test for unaligned floor or ceiling
5211 ret
5212 ;-----------------------------------------------------------------------------
5213
5214 ;-----------------------------------------------------------------------------
5215 ; Translate_Address : virtual address in eax; output (physical addr) in eax
5216 ;-----------------------------------------------------------------------------
5217 align GRAIN, db 0x90
5218 _Virt_To_Phys:
5219 bt eax, 31 ; CF := 31st (top) bit of vAddr
5220 jc _Above_7FFFFFFF ; If 31st bit = 1, kseg 0/1/2; else:
5221 ;; 0x00000000 <= vAddr <= 0x7FFFFFFF (kuseg) :
5222 bt CP0_Status, CP0St_ERL ; CF := CP0St_ERL Flag
5223 jnc _TLB_Lookup ; If ERL = 0: TLB Lookup required; else:
5224 jmp _No_Tlb_Lookup ; pAddr is equal to vAddr, return.
5225 _Above_7FFFFFFF:
5226 bt eax, 30 ; CF := 30th (2nd from top) bt of vAddr
5227 jc _Above_BFFFFFFF ; If 30th bit = 1 : kseg2; else:
5228 ;; 0x80000000 <= vAddr <= 0x9FFFFFFF (kseg0) :
5229 ;; 0xA0000000 <= vAddr <= 0xBFFFFFFF (kseg1) :
5230 and eax, 0x1FFFFFFF ; kseg0 and kseg1: clear top 3 bits,
5231 jmp _No_Tlb_Lookup ; i.e. pAddr := bottom 29 bts of vAddr.
5232 _Above_BFFFFFFF: ;; 0xC0000000 <= vAddr <= 0xFFFFFFFF (kseg2) :
5233 bt CP0_Status, CP0St_UM ; CF := CP0St_UM Flag
5234 jnc _TLB_Lookup ; If UM = 0: K. Mode, so do TLB; else:
5235 test CP0_Status, (1 << CP0St_EXL) | (1 << CP0St_ERL) ; EXL or ERL
5236 jnz _TLB_Lookup ; If EXL && ERL, K. Mode, do TLB
5237 ;; Else: vAddr is in kseg2, but we are NOT in Kernel Mode:
5238 Flg_Get IsWriting ; Is Writing?
5239 jc _V2P_Eggog_Wr ; If so, we want to set AdES;
5240 _V2P_Eggog_Rd: ; ... otherwise, set AdEL.
5241 SetEXC EXC_AdEL ; Fetch address error.
5242 jmp _V2P_Eggog_Fin ; Proceed to abort.
5243 _V2P_Eggog_Wr:
5244 SetEXC EXC_AdES ; Store address error.
5245 _V2P_Eggog_Fin:
5246 ;; Will go into exception handler instead of back to _Virt_xxx etc
5247 add rsp, 16 ; squelch return to _Virt_xxx and its caller
5248 push _Handle_Exception ; 'return' directly to exc handler.
5249 _No_Tlb_Lookup:
5250 Flg_Off IsWriting ; Consume 'is writing' flag.
5251 ret ; Done.
5252 _TLB_Lookup: ; TLB Lookup Required:
5253 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5254 ;; Save ebx, ecx, edx, AUX, to xmm ;;
5255 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5256 movd xmm0, ebx
5257 movd xmm1, ecx
5258 movd xmm2, edx
5259 movd xmm3, AUX
5260 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5261 Flg_Off ExcWasTLBNoMatch ; Clear the ExcWasTLBNoMatch Flag
5262 ;; Get the active ASID:
5263 mov edx, Sr(CP0_EntryHi) ; edx := CP0_EntryHi
5264 and edx, 0xFF ; edx := edx & 0xFF (get current ASID)
5265 ;; For each slot in table (0 .. 15), attempt lookup
5266 xor AUX, AUX ; Start with the 0-th entry in table
5267 _Lookup_TLB_E:
5268 mov ecx, eax ; ecx := eax (vAddr)
5269 and ecx, 0xFFFFF000 ; ecx := ecx & 0xFFFFF000
5270 shr ecx, 13 ; ecx := ecx >> 13 (get vAddr's Tag)
5271 mov ebx, TLB_E(AUX) ; ebx := current TLB entry
5272 and ebx, TLB_VPN2_Mask ; get VPN2 of this entry
5273 cmp ebx, ecx ; cmp(entry.VPN2, vAddr.tag)
5274 jne _Lookup_TLB_E_Not_Here ; if entry.VPN2 != vAddr.tag: no match
5275 mov ebx, TLB_E(AUX) ; ebx := current TLB entry
5276 bt ebx, TLB_G ; is entry.G = 1?
5277 jc _Lookup_TLB_E_Match ; then match.
5278 shr ebx, TLB_ASID_Shift ; ebx := ebx >> TLB_ASID_Shift
5279 and ebx, TLB_ASID_Mask ; ebx := entry.ASID
5280 cmp ebx, edx ; entry.ASID = current ASID ?
5281 jne _Lookup_TLB_E_Not_Here ; if neither G=1 nor ASID match.
5282 mov ebx, TLB_E(AUX) ; ebx := current TLB entry
5283 _Lookup_TLB_E_Match: ; TLB Match:
5284 bt eax, 12 ; Test odd/even junior bit
5285 jc _Lookup_TLB_E_Match_Odd ; If odd: test V1, D1
5286 _Lookup_TLB_E_Match_Even: ; If even: test V0, D0
5287 lea ecx, TLB_PFN_E(AUX) ; prepare to load even PFN entry
5288 bt ebx, TLB_V0 ; Is entry.V0=1 ?
5289 jnc _Lookup_TLB_E_Invalid ; If not, TLBRET_INVALID
5290 bt ebx, TLB_D0 ; Is entry.D0=1 ?
5291 jc _Lookup_TLB_E_Match_Yes ; If entry.D0=1, then Match Yes
5292 jmp _Lookup_TLB_E_Match_Wr ; else, go to 'is writing?'
5293 _Lookup_TLB_E_Match_Odd: ; Odd bit:
5294 lea ecx, TLB_PFN_O(AUX) ; prepare to load odd PFN entry
5295 bt ebx, TLB_V1 ; Is entry.V1=1 ?
5296 jnc _Lookup_TLB_E_Invalid ; If not, TLBRET_INVALID
5297 bt ebx, TLB_D1 ; Is entry.D1=1 ?
5298 jc _Lookup_TLB_E_Match_Yes ; If entry.D1=1, then Match Yes
5299 _Lookup_TLB_E_Match_Wr:
5300 Flg_Get IsWriting ; Is Writing?
5301 jnc _Lookup_TLB_E_Match_Yes ; If not writing, go to Match Yes
5302 _Lookup_TLB_E_Dirty: ; ... else, Dirty:
5303 SetEXC EXC_Mod ; Set the EXC_Mod Exception
5304 jmp _Lookup_TLB_E_WriteExtr ; Write the 'extra data' and finish.
5305 _Lookup_TLB_E_Match_Yes: ; This is the 'success' case
5306 mov ebx, dword [ecx] ; Actually load the current PFN entry
5307 and eax, 0xFFF ; vAddr := vAddr & 0xFFF
5308 or eax, ebx ; vAddr := vAddr | entry.PFN[lowbit]
5309 jmp _Lookup_TLB_Done ; vAddr is now correct pAddr, done.
5310 _Lookup_TLB_E_Not_Here: ; try next one in the table, if any
5311 inc AUX ; index := index + 1
5312 cmp AUX, TLB_ENTRIES_COUNT ; see if still in range 0 .. n-1
5313 jb _Lookup_TLB_E ; if in range, go to next entry
5314 ;; ... else:
5315 Flg_On ExcWasTLBNoMatch ; Set the ExcWasTLBNoMatch Flag
5316 ;; ... now drop down into 'invalid' :
5317 _Lookup_TLB_E_Invalid:
5318 Flg_Get IsWriting ; Was Writing?
5319 jc _Lookup_TLB_E_Invalid_W ; If so, we want to set EXC_TLBS
5320 _Lookup_TLB_E_Invalid_R: ; Otherwise, set EXC_TLBL exception
5321 SetEXC EXC_TLBL ; Set the EXC_TLBL Exception
5322 jmp _Lookup_TLB_E_WriteExtr ; Write the 'extra data' and finish.
5323 _Lookup_TLB_E_Invalid_W:
5324 SetEXC EXC_TLBS ; Set the EXC_TLBS Exception
5325 ;; then drop down to 'write extra' :
5326 _Lookup_TLB_E_WriteExtr: ; Write the 'extra data' and finish
5327 mov Sr(CP0_BadVAddr), eax ; CP0_BadVAddr := vAddr
5328 mov ecx, eax ; ecx := vAddr
5329 mov ebx, Sr(CP0_Context) ; ebx := CP0_Context
5330 and ebx, ~0x007FFFFF ; ebx := ebx & ~0x007FFFFF
5331 shr ecx, 9 ; ecx := ecx >> 9
5332 and ecx, 0x007FFFF0 ; ecx := ecx & 0x007FFFF0
5333 or ebx, ecx ; ebx := ebx | ecx
5334 mov Sr(CP0_Context), ebx ; CP0_Context := ebx
5335 mov ecx, eax ; ecx := vAddr
5336 mov ebx, Sr(CP0_EntryHi) ; ebx := CP0_EntryHi
5337 and ebx, 0xFF ; ebx := ebx & 0xFF
5338 and ecx, 0xFFFFE000 ; ecx := ecx & 0xFFFFE000
5339 or ebx, ecx ; ebx := ebx | ecx
5340 mov Sr(CP0_EntryHi), ebx ; CP0_EntryHi := ebx
5341 ;; Will go into exception handler instead of back to _Virt_xxx etc
5342 add rsp, 16 ; squelch return to _Virt_xxx and its caller
5343 push _Handle_Exception ; 'return' directly to exc handler.
5344 ;; and drop into 'done' :
5345 _Lookup_TLB_Done:
5346 Flg_Off IsWriting ; Consume 'is writing' flag.
5347 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5348 ;; Restore ebx, ecx, edx, AUX, from xmm ;;
5349 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5350 movd ebx, xmm0
5351 movd ecx, xmm1
5352 movd edx, xmm2
5353 movd AUX, xmm3
5354 ret
5355 ;-----------------------------------------------------------------------------
5356
5357 ;-----------------------------------------------------------------------------
5358 ; ReadWord - Source Address (Virtual) is EAX; Resulting Word Read is EAX.
5359 ;-----------------------------------------------------------------------------
5360 ; TODO: 1) is the 'unaligned' case in fact physically possible?
5361 ; 2) would go faster if used tmp instead of self-clobbering rax ?
5362 align GRAIN, db 0x90
5363 _Virt_Read_Word:
5364 call _Virt_To_Phys ; Transform vAddr to pAddr
5365 test eax, 0x3 ; Are any of the bottom 2 bits set?
5366 jnz _V_Rd_Word_Unaligned ; If yes, go to eggog. Else:
5367 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5368 ;; If pAddr is in Memory-Mapped Device space:
5369 JMP_If_In eax, MMIO_BASE, MMIO_TOP, _Phys_Device_Read_Word
5370 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5371 add rax, RAM_Floor ; Calculate the target PC RAM addr
5372 cmp rax, RAM_Ceiling ; compare the above with RAM ceiling
5373 jnb _V_Rd_Word_Hit_Ceiling ; if not below: RAM ceiling eggog!
5374 ;; Address is valid, so load the word:
5375 mov eax, dword [rax] ; eax := dword [rax]
5376 ret ; Done, return with read result in eax.
5377 _V_Rd_Word_Unaligned: ;; TODO: print address
5378 ACHTUNG "Virt_Read_Word: Unaligned Physical Address!"
5379 jmp _V_Rd_Word_Eggog ; Go to eggogology
5380 _V_Rd_Word_Hit_Ceiling: ;; TODO: print address
5381 ACHTUNG "Virt_Read_Word: Hit RAM Ceiling!"
5382 _V_Rd_Word_Eggog:
5383 SetEXC EXC_AdEL ; Fetch address error.
5384 ;; Will go into exception handler instead of back to caller
5385 add rsp, 8 ; squelch return to original caller
5386 push _Handle_Exception ; 'return' directly to exc handler.
5387 ret ; Go there.
5388 ;-----------------------------------------------------------------------------
5389
5390 ;-----------------------------------------------------------------------------
5391 ; WriteWord - Destination Address (Virtual) is EAX; Word to be Written is TMP.
5392 ;-----------------------------------------------------------------------------
5393 ; TODO: 1) is the 'unaligned' case in fact physically possible?
5394 ; 2) would go faster if used tmp instead of self-clobbering rax ?
5395 ; 3) do we need to explicitly zero-extend rax here?
5396 align GRAIN, db 0x90
5397 _Virt_Write_Word:
5398 Flg_On IsWriting ; Tell the translator that we're writing
5399 call _Virt_To_Phys ; Transform vAddr to pAddr
5400 test eax, 0x3 ; Are any of the bottom 2 bits set?
5401 jnz _V_Wr_Word_Unaligned ; If yes, go to eggog. Else:
5402 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5403 ;; If pAddr is in Memory-Mapped Device space:
5404 JMP_If_In eax, MMIO_BASE, MMIO_TOP, _Phys_Device_Write_Word
5405 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5406 add rax, RAM_Floor ; Calculate the target PC RAM addr
5407 cmp rax, RAM_Ceiling ; compare the above with RAM ceiling
5408 jnb _V_Wr_Word_Hit_Ceiling ; if not below: RAM ceiling eggog!
5409 ;; Address is valid, so write the word:
5410 mov dword [rax], TMP ; dword [rax] := TMP
5411 ret ; Done.
5412 _V_Wr_Word_Unaligned: ;; TODO: print address
5413 ACHTUNG "Virt_Write_Word: Unaligned Physical Address!"
5414 jmp _V_Wr_Word_Eggog
5415 _V_Wr_Word_Hit_Ceiling: ;; TODO: print address
5416 ACHTUNG "Virt_Write_Word: Hit RAM Ceiling!"
5417 _V_Wr_Word_Eggog:
5418 SetEXC EXC_AdES ; Store address error.
5419 ;; Will go into exception handler instead of back to caller
5420 add rsp, 8 ; squelch return to original caller
5421 push _Handle_Exception ; 'return' directly to exc handler.
5422 ret ; Go there.
5423 ;-----------------------------------------------------------------------------
5424
5425 ;-----------------------------------------------------------------------------
5426 ; ReadByte - Source Address (Virtual) is EAX; Resulting Byte Read is EAX.
5427 ;-----------------------------------------------------------------------------
5428 align GRAIN, db 0x90
5429 _Virt_Read_Byte:
5430 call _Virt_To_Phys ; Transform vAddr to pAddr
5431 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5432 ;; If pAddr is in Memory-Mapped Device space:
5433 JMP_If_In eax, MMIO_BASE, MMIO_TOP, _Phys_Device_Read_Byte
5434 ;;;;;;;;;;;;;;;;;; ENDIANISM ;;;;;;;;;;;;;;;;;;
5435 %ifdef LITTLE_ENDIAN
5436 ;; little -- do nothing
5437 %else
5438 ;; big -- flip :
5439 xor eax, 0x3 ; Flip the 3 unalignment bits.
5440 %endif
5441 ;;;;;;;;;;;;;;;;;; ENDIANISM ;;;;;;;;;;;;;;;;;;
5442 add rax, RAM_Floor ; Calculate the target PC RAM addr
5443 cmp rax, RAM_Ceiling ; compare the above with RAM ceiling
5444 jnb _V_Rd_Byte_Hit_Ceiling ; if not below: RAM ceiling eggog!
5445 ;; Address is valid, so proceed to load:
5446 movzx ax, byte [rax] ; ax := byte [rax]
5447 and eax, 0xFF ; keep only bottom byte
5448 ret ; Done, return with read result in eax.
5449 _V_Rd_Byte_Hit_Ceiling:
5450 ACHTUNG "Virt_Read_Byte: Hit RAM Ceiling!" ;; TODO: print address
5451 SetEXC EXC_AdEL ; Fetch address error.
5452 ;; Will go into exception handler instead of back to caller
5453 add rsp, 8 ; squelch return to original caller
5454 push _Handle_Exception ; 'return' directly to exc handler.
5455 ret ; Go there.
5456 ;-----------------------------------------------------------------------------
5457
5458 ;-----------------------------------------------------------------------------
5459 ; WriteByte - Destination Address (Virtual) is EAX; Byte to be Written is DL.
5460 ;-----------------------------------------------------------------------------
5461 align GRAIN, db 0x90
5462 _Virt_Write_Byte:
5463 Flg_On IsWriting ; Tell the translator that we're writing
5464 call _Virt_To_Phys ; Transform vAddr to pAddr
5465 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5466 ;; If pAddr is in Memory-Mapped Device space:
5467 JMP_If_In eax, MMIO_BASE, MMIO_TOP, _Phys_Device_Write_Byte
5468 ;;;;;;;;;;;;;;;;;; ENDIANISM ;;;;;;;;;;;;;;;;;;
5469 %ifdef LITTLE_ENDIAN
5470 ;; little -- do nothing
5471 %else
5472 ;; big -- flip :
5473 xor eax, 0x3 ; Flip the 3 unalignment bits.
5474 %endif
5475 ;;;;;;;;;;;;;;;;;; ENDIANISM ;;;;;;;;;;;;;;;;;;
5476 add rax, RAM_Floor ; Calculate the target PC RAM addr
5477 cmp rax, RAM_Ceiling ; compare the above with RAM ceiling
5478 jnb _V_Wr_Byte_Hit_Ceiling ; if not below: RAM ceiling eggog!
5479 ;; Address is valid, so write the byte:
5480 mov byte [rax], DL ; dword [rax] := TMP
5481 ret ; Done.
5482 _V_Wr_Byte_Hit_Ceiling:
5483 ACHTUNG "Virt_Write_Byte: Hit RAM Ceiling!" ;; TODO: print address
5484 SetEXC EXC_AdES ; Store address error.
5485 ;; Will go into exception handler instead of back to caller
5486 add rsp, 8 ; squelch return to original caller
5487 push _Handle_Exception ; 'return' directly to exc handler.
5488 ret ; Go there.
5489 ;-----------------------------------------------------------------------------
5490
5491 ;-----------------------------------------------------------------------------
5492 ; Write TLB Entry at the given index. Index (0 .. 15) is in AUX.
5493 ; Kills eax, ebx, ecx, edx.
5494 ;-----------------------------------------------------------------------------
5495 _write_tlb_entry:
5496 mov edx, Sr(CP0_EntryHi) ; edx := CP0_EntryHi
5497 mov ecx, edx ; ecx := edx
5498 shr ecx, 13 ; ecx := ecx >> 13 to get VPN2
5499 and edx, TLB_ASID_Mask ; edx := edx & 0xFF to get ASID
5500 shl edx, TLB_ASID_Shift ; edx := edx << 19 to put ASID in place
5501 or ecx, edx ; now we have VPN2 and ASID in ecx
5502 ;; done with edx, can reuse
5503 mov edx, Sr(CP0_EntryLo0) ; edx := CP0_EntryLo0
5504 mov ebx, Sr(CP0_EntryLo1) ; ebx := CP0_EntryLo1
5505 ;; get G:
5506 mov eax, edx ; eax := CP0_EntryLo0
5507 and eax, ebx ; eax := eax & CP0_EntryLo1
5508 and eax, 0x1 ; eax := eax & 1 to get G
5509 shl eax, TLB_G ; move G bit into position
5510 or ecx, eax ; ecx := ecx | eax to put in G bit
5511 ;; now ecx contains VPN2, ASID, G
5512 ;; Get V0 from CP0_EntryLo0 and put in ecx where belongs:
5513 mov eax, edx ; eax := CP0_EntryLo0
5514 and eax, 0x2 ; eax := eax & 0x2 to get V0 bit
5515 shl eax, (TLB_V0 - 1) ; put V0 bit in position
5516 or ecx, eax ; ecx := ecx | eax to put in V0 bit
5517 ;; Get D0 from CP0_EntryLo0 and put in ecx where belongs:
5518 mov eax, edx ; eax := CP0_EntryLo0
5519 and eax, 0x4 ; eax := eax & 0x4 to get D0 bit
5520 shl eax, (TLB_D0 - 2) ; put D0 bit in position
5521 or ecx, eax ; ecx := ecx | eax to put in D0 bit
5522 ;; Get V1 from CP0_EntryLo1 and put in ecx where belongs:
5523 mov eax, ebx ; eax := CP0_EntryLo1
5524 and eax, 0x2 ; eax := eax & 0x2 to get V1 bit
5525 shl eax, (TLB_V1 - 1) ; put V1 bit in position
5526 or ecx, eax ; ecx := ecx | eax to put in V1 bit
5527 ;; Get D1 from CP0_EntryLo1 and put in ecx where belongs:
5528 mov eax, ebx ; eax := CP0_EntryLo1
5529 and eax, 0x4 ; eax := eax & 0x4 to get D1 bit
5530 shl eax, (TLB_D1 - 2) ; put D1 bit in position
5531 or ecx, eax ; ecx := ecx | eax to put in D1 bit
5532 ;; Write the TLB entry to the given index (in AUX) :
5533 and AUX, 0xF ; Index of TLB entry is bottom 4 bits
5534 mov TLB_E(AUX), ecx ; Write TLB entry in ecx to n-th slot.
5535 ;; Transform CP0_EntryLo0 (edx) into PFN0:
5536 shr edx, 6
5537 and edx, 0xFFFFF
5538 shl edx, 12
5539 ;; Transform CP0_EntryLo1 (ebx) into PFN1:
5540 shr ebx, 6
5541 and ebx, 0xFFFFF
5542 shl ebx, 12
5543 ;; Store PFN:
5544 mov TLB_PFN_E(AUX), edx ; Store PFN0
5545 mov TLB_PFN_O(AUX), ebx ; Store PFN1
5546 ret ; Done.
5547 ;-----------------------------------------------------------------------------