/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *   Mupen64plus - linkage_x86.s                                           *
 *   Copyright (C) 2009-2011 Ari64                                         *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
	.file	"linkage_x86.s"
	.bss
	.align 4

	.section	.rodata
	.text
.globl dyna_linker
	.hidden dyna_linker
	.type	dyna_linker, @function
dyna_linker:
	/* eax = virtual target address */
	/* ebx = instruction to patch */
	mov	%eax, %edi
	mov	%eax, %ecx
	shr	$12, %edi
	cmp	$0xC0000000, %eax
	cmovge	tlb_LUT_r(,%edi,4), %ecx
	test	%ecx, %ecx
	cmovz	%eax, %ecx
	xor	$0x80000000, %ecx
	mov	$2047, %edx
	shr	$12, %ecx
	and	%ecx, %edx
	or	$2048, %edx
	cmp	%edx, %ecx
	cmova	%edx, %ecx
	/* jump_in lookup */
	mov	jump_in(,%ecx,4), %edx
.A1:
	test	%edx, %edx
	je	.A3
	mov	(%edx), %edi
	xor	%eax, %edi
	or	4(%edx), %edi
	je	.A2
	movl	12(%edx), %edx
	jmp	.A1
.A2:
	mov	(%ebx), %edi
	mov	%esi, %ebp
	lea	4(%ebx,%edi,1), %esi
	mov	%eax, %edi
	pusha
	call	add_link
	popa
	mov	8(%edx), %edi
	mov	%ebp, %esi
	lea	-4(%edi), %edx
	subl	%ebx, %edx
	movl	%edx, (%ebx)
	jmp	*%edi
.A3:
	/* hash_table lookup */
	mov	%eax, %edi
	mov	%eax, %edx
	shr	$16, %edi
	shr	$12, %edx
	xor	%eax, %edi
	and	$2047, %edx
	movzwl	%di, %edi
	shl	$4, %edi
	cmp	$2048, %ecx
	cmovc	%edx, %ecx
	cmp	hash_table(%edi), %eax
	jne	.A5
.A4:
	mov	hash_table+4(%edi), %edx
	jmp	*%edx
.A5:
	cmp	hash_table+8(%edi), %eax
	lea	8(%edi), %edi
	je	.A4
	/* jump_dirty lookup */
	mov	jump_dirty(,%ecx,4), %edx
.A6:
	testl	%edx, %edx
	je	.A8
	mov	(%edx), %ecx
	xor	%eax, %ecx
	or	4(%edx), %ecx
	je	.A7
	movl	12(%edx), %edx
	jmp	.A6
.A7:
	mov	8(%edx), %edx
	/* hash_table insert */
	mov	hash_table-8(%edi), %ebx
	mov	hash_table-4(%edi), %ecx
	mov	%eax, hash_table-8(%edi)
	mov	%edx, hash_table-4(%edi)
	mov	%ebx, hash_table(%edi)
	mov	%ecx, hash_table+4(%edi)
	jmp	*%edx
.A8:
	mov	%eax, %edi
	pusha
	call	new_recompile_block
	test	%eax, %eax
	popa
	je	dyna_linker
	/* pagefault */
	mov	%eax, %ebx
	mov	$0x08, %ecx
	.size	dyna_linker, .-dyna_linker

	.type	exec_pagefault, @function
exec_pagefault:
	/* eax = instruction pointer */
	/* ebx = fault address */
	/* ecx = cause */
	mov	g_cp0_regs+48, %edx
	add	$-12, %esp
	mov	g_cp0_regs+16, %edi
	or	$2, %edx
	mov	%ebx, g_cp0_regs+32 /* BadVAddr */
	and	$0xFF80000F, %edi
	mov	%edx, g_cp0_regs+48 /* Status */
	mov	%ecx, g_cp0_regs+52 /* Cause */
	mov	%eax, g_cp0_regs+56 /* EPC */
	mov	%ebx, %ecx
	shr	$9, %ebx
	and	$0xFFFFE000, %ecx
	and	$0x007FFFF0, %ebx
	mov	%ecx, g_cp0_regs+40 /* EntryHI */
	or	%ebx, %edi
	mov	%edi, g_cp0_regs+16 /* Context */
	push	$0x80000000
	call	get_addr_ht
	add	$16, %esp
	jmp	*%eax
	.size	exec_pagefault, .-exec_pagefault

/* Special dynamic linker for the case where a page fault
   may occur in a branch delay slot */
.globl dyna_linker_ds
	.hidden dyna_linker_ds
	.type	dyna_linker_ds, @function
dyna_linker_ds:
	mov	%eax, %edi
	mov	%eax, %ecx
	shr	$12, %edi
	cmp	$0xC0000000, %eax
	cmovge	tlb_LUT_r(,%edi,4), %ecx
	test	%ecx, %ecx
	cmovz	%eax, %ecx
	xor	$0x80000000, %ecx
	mov	$2047, %edx
	shr	$12, %ecx
	and	%ecx, %edx
	or	$2048, %edx
	cmp	%edx, %ecx
	cmova	%edx, %ecx
	/* jump_in lookup */
	mov	jump_in(,%ecx,4), %edx
.B1:
	test	%edx, %edx
	je	.B3
	mov	(%edx), %edi
	xor	%eax, %edi
	or	4(%edx), %edi
	je	.B2
	movl	12(%edx), %edx
	jmp	.B1
.B2:
	mov	(%ebx), %edi
	mov	%esi, %ecx
	lea	4(%ebx,%edi,1), %esi
	mov	%eax, %edi
	pusha
	call	add_link
	popa
	mov	8(%edx), %edi
	mov	%ecx, %esi
	lea	-4(%edi), %edx
	subl	%ebx, %edx
	movl	%edx, (%ebx)
	jmp	*%edi
.B3:
	/* hash_table lookup */
	mov	%eax, %edi
	mov	%eax, %edx
	shr	$16, %edi
	shr	$12, %edx
	xor	%eax, %edi
	and	$2047, %edx
	movzwl	%di, %edi
	shl	$4, %edi
	cmp	$2048, %ecx
	cmovc	%edx, %ecx
	cmp	hash_table(%edi), %eax
	jne	.B5
.B4:
	mov	hash_table+4(%edi), %edx
	jmp	*%edx
.B5:
	cmp	hash_table+8(%edi), %eax
	lea	8(%edi), %edi
	je	.B4
	/* jump_dirty lookup */
	mov	jump_dirty(,%ecx,4), %edx
.B6:
	testl	%edx, %edx
	je	.B8
	mov	(%edx), %ecx
	xor	%eax, %ecx
	or	4(%edx), %ecx
	je	.B7
	movl	12(%edx), %edx
	jmp	.B6
.B7:
	mov	8(%edx), %edx
	/* hash_table insert */
	mov	hash_table-8(%edi), %ebx
	mov	hash_table-4(%edi), %ecx
	mov	%eax, hash_table-8(%edi)
	mov	%edx, hash_table-4(%edi)
	mov	%ebx, hash_table(%edi)
	mov	%ecx, hash_table+4(%edi)
	jmp	*%edx
.B8:
	mov	%eax, %edi
	and	$0xFFFFFFF8, %edi
	inc	%edi
	pusha
	call	new_recompile_block
	test	%eax, %eax
	popa
	je	dyna_linker_ds
	/* pagefault */
	and	$0xFFFFFFF8, %eax
	mov	$0x80000008, %ecx /* High bit set indicates pagefault in delay slot */
	mov	%eax, %ebx
	sub	$4, %eax
	jmp	exec_pagefault
	.size	dyna_linker_ds, .-dyna_linker_ds

.globl jump_vaddr_eax
	.hidden jump_vaddr_eax
	.type	jump_vaddr_eax, @function
jump_vaddr_eax:
	mov	%eax, %edi
	jmp	jump_vaddr_edi
	.size	jump_vaddr_eax, .-jump_vaddr_eax
.globl jump_vaddr_ecx
	.hidden jump_vaddr_ecx
	.type	jump_vaddr_ecx, @function
jump_vaddr_ecx:
	mov	%ecx, %edi
	jmp	jump_vaddr_edi
	.size	jump_vaddr_ecx, .-jump_vaddr_ecx
.globl jump_vaddr_edx
	.hidden jump_vaddr_edx
	.type	jump_vaddr_edx, @function
jump_vaddr_edx:
	mov	%edx, %edi
	jmp	jump_vaddr_edi
	.size	jump_vaddr_edx, .-jump_vaddr_edx
.globl jump_vaddr_ebx
	.hidden jump_vaddr_ebx
	.type	jump_vaddr_ebx, @function
jump_vaddr_ebx:
	mov	%ebx, %edi
	jmp	jump_vaddr_edi
	.size	jump_vaddr_ebx, .-jump_vaddr_ebx
.globl jump_vaddr_ebp
	.hidden jump_vaddr_ebp
	.type	jump_vaddr_ebp, @function
jump_vaddr_ebp:
	mov	%ebp, %edi
	.size	jump_vaddr_ebp, .-jump_vaddr_ebp
.globl jump_vaddr_edi
	.hidden jump_vaddr_edi
	.type	jump_vaddr_edi, @function
jump_vaddr_edi:
	mov	%edi, %eax
	.size	jump_vaddr_edi, .-jump_vaddr_edi

	.type	jump_vaddr, @function
jump_vaddr:
  /* Check hash table */
	shr	$16, %eax
	xor	%edi, %eax
	movzwl	%ax, %eax
	shl	$4, %eax
	cmp	hash_table(%eax), %edi
	jne	.C2
.C1:
	mov	hash_table+4(%eax), %edi
	jmp	*%edi
.C2:
	cmp	hash_table+8(%eax), %edi
	lea	8(%eax), %eax
	je	.C1
  /* No hit on hash table, call compiler */
	add	$-12, %esp
	push	%edi
	mov	%esi, cycle_count /* CCREG */
	call	get_addr
	mov	cycle_count, %esi
	add	$16, %esp
	jmp	*%eax
	.size	jump_vaddr, .-jump_vaddr

.globl verify_code_ds
	.hidden verify_code_ds
	.type	verify_code_ds, @function
verify_code_ds:
	mov	%ebp, branch_target
	.size	verify_code_ds, .-verify_code_ds

.globl verify_code_vm
	.hidden verify_code_vm
	.type	verify_code_vm, @function
verify_code_vm:
	/* eax = source (virtual address) */
	/* ebx = target */
	/* ecx = length */
	cmp	$0xC0000000, %eax
	jl	verify_code
	mov	%eax, %edx
	lea	-1(%eax,%ecx,1), %ebp
	shr	$12, %edx
	shr	$12, %ebp
	mov	memory_map(,%edx,4), %edi
	test	%edi, %edi
	js	.D5
	lea	(%eax,%edi,4), %eax
.D1:
	xor	memory_map(,%edx,4), %edi
	shl	$2, %edi
	jne	.D5
	mov	memory_map(,%edx,4), %edi
	inc	%edx
	cmp	%ebp, %edx
	jbe	.D1
	.size	verify_code_vm, .-verify_code_vm

.globl verify_code
	.hidden verify_code
	.type	verify_code, @function
verify_code:
	/* eax = source */
	/* ebx = target */
	/* ecx = length */
	mov	-4(%eax,%ecx,1), %edi
	xor	-4(%ebx,%ecx,1), %edi
	jne	.D5
	mov	%ecx, %edx
	add	$-4, %ecx
	je	.D3
	test	$4, %edx
	cmove	%edx, %ecx
	mov	%esi, cycle_count
.D2:
	mov	-4(%eax,%ecx,1), %edx
	mov	-4(%ebx,%ecx,1), %ebp
	mov	-8(%eax,%ecx,1), %esi
	xor	%edx, %ebp
	mov	-8(%ebx,%ecx,1), %edi
	jne	.D4
	xor	%esi, %edi
	jne	.D4
	add	$-8, %ecx
	jne	.D2
	mov	cycle_count, %esi
	mov	branch_target, %ebp
.D3:
	ret
.D4:
	mov	cycle_count, %esi
.D5:
	mov	branch_target, %ebp
	push	%esi /* for stack alignment, unused */
	push	8(%esp)
	call	get_addr
	add	$16, %esp /* pop stack */
	jmp	*%eax
	.size	verify_code, .-verify_code

.globl cc_interrupt
	.hidden cc_interrupt
	.type	cc_interrupt, @function
cc_interrupt:
	add	last_count, %esi
	add	$-28, %esp /* Align stack */
	mov	%esi, g_cp0_regs+36 /* Count */
	shr	$19, %esi
	movl	$0, pending_exception
	and	$0x7f, %esi
	cmpl	$0, restore_candidate(,%esi,4)
	jne	.E4
.E1:
	call	gen_interupt
	mov	g_cp0_regs+36, %esi
	mov	next_interupt, %eax
	mov	pending_exception, %ebx
	mov	stop, %ecx
	add	$28, %esp
	mov	%eax, last_count
	sub	%eax, %esi
	test	%ecx, %ecx
	jne	.E3
	test	%ebx, %ebx
	jne	.E2
	ret
.E2:
	add	$-8, %esp
	mov	pcaddr, %edi
	mov	%esi, cycle_count /* CCREG */
	push	%edi
	call	get_addr_ht
	mov	cycle_count, %esi
	add	$16, %esp
	jmp	*%eax
.E3:
	add	$16, %esp /* pop stack */
	pop	%edi /* restore edi */
	pop	%esi /* restore esi */
	pop	%ebx /* restore ebx */
	pop	%ebp /* restore ebp */
	ret	     /* exit dynarec */
.E4:
	/* Move 'dirty' blocks to the 'clean' list */
	mov	restore_candidate(,%esi,4), %ebx
	mov	%esi, %ebp
	movl	$0, restore_candidate(,%esi,4)
	shl	$5, %ebp
.E5:
	shr	$1, %ebx
	jnc	.E6
	mov	%ebp, (%esp)
	call	clean_blocks
.E6:
	inc	%ebp
	test	$31, %ebp
	jne	.E5
	jmp	.E1
	.size	cc_interrupt, .-cc_interrupt

.globl do_interrupt
	.hidden do_interrupt
	.type	do_interrupt, @function
do_interrupt:
	mov	pcaddr, %edi
	add	$-12, %esp
	push	%edi
	call	get_addr_ht
	add	$16, %esp
	mov	g_cp0_regs+36, %esi
	mov	next_interupt, %ebx
	mov	%ebx, last_count
	sub	%ebx, %esi
	add	$2, %esi
	jmp	*%eax
	.size	do_interrupt, .-do_interrupt

.globl fp_exception
	.hidden fp_exception
	.type	fp_exception, @function
fp_exception:
	mov	$0x1000002c, %edx
.E7:
	mov	g_cp0_regs+48, %ebx
	add	$-12, %esp
	or	$2, %ebx
	mov	%ebx, g_cp0_regs+48 /* Status */
	mov	%edx, g_cp0_regs+52 /* Cause */
	mov	%eax, g_cp0_regs+56 /* EPC */
	push    $0x80000180
	call	get_addr_ht
	add	$16, %esp
	jmp	*%eax
	.size	fp_exception, .-fp_exception

.globl fp_exception_ds
	.hidden fp_exception_ds
	.type	fp_exception_ds, @function
fp_exception_ds:
	mov	$0x9000002c, %edx /* Set high bit if delay slot */
	jmp	.E7
	.size	fp_exception_ds, .-fp_exception_ds

.globl jump_syscall
	.hidden jump_syscall
	.type	jump_syscall, @function
jump_syscall:
	mov	$0x20, %edx
	mov	g_cp0_regs+48, %ebx
	add	$-12, %esp
	or	$2, %ebx
	mov	%ebx, g_cp0_regs+48 /* Status */
	mov	%edx, g_cp0_regs+52 /* Cause */
	mov	%eax, g_cp0_regs+56 /* EPC */
	push    $0x80000180
	call	get_addr_ht
	add	$16, %esp
	jmp	*%eax
	.size	jump_syscall, .-jump_syscall

.globl jump_eret
	.hidden jump_eret
	.type	jump_eret, @function
jump_eret:
	mov	g_cp0_regs+48, %ebx /* Status */
	add	last_count, %esi
	and	$0xFFFFFFFD, %ebx
	mov	%esi, g_cp0_regs+36 /* Count */
	mov	%ebx, g_cp0_regs+48 /* Status */
	call	check_interupt
	mov	next_interupt, %eax
	mov	g_cp0_regs+36, %esi
	mov	%eax, last_count
	sub	%eax, %esi
	mov	g_cp0_regs+56, %eax /* EPC */
	jns	.E11
.E8:
	mov	$248, %ebx
	xor	%edi, %edi
.E9:
	mov	reg(%ebx), %ecx
	mov	reg+4(%ebx), %edx
	sar	$31, %ecx
	xor	%ecx, %edx
	neg	%edx
	adc	%edi, %edi
	sub	$8, %ebx
	jne	.E9
	mov	hi(%ebx), %ecx
	mov	hi+4(%ebx), %edx
	sar	$31, %ecx
	xor	%ecx, %edx
	jne	.E10
	mov	lo(%ebx), %ecx
	mov	lo+4(%ebx), %edx
	sar	$31, %ecx
	xor	%ecx, %edx
.E10:
	neg	%edx
	adc	%edi, %edi
	add	$-8, %esp
	push	%edi
	push	%eax
	mov	%esi, cycle_count
	call	get_addr_32
	mov	cycle_count, %esi
	add	$16, %esp
	jmp	*%eax
.E11:
	mov	%eax, pcaddr
	call	cc_interrupt
	mov	pcaddr, %eax
	jmp	.E8
	.size	jump_eret, .-jump_eret

.globl new_dyna_start
	.hidden new_dyna_start
	.type	new_dyna_start, @function
new_dyna_start:
	push	%ebp
	push	%ebx
	push	%esi
	push	%edi
	add	$-8, %esp /* align stack */
	push	$0xa4000040
	call	new_recompile_block
	movl	next_interupt, %edi
	movl	g_cp0_regs+36, %esi
	movl	%edi, last_count
	subl	%edi, %esi
	jmp	*base_addr
	.size	new_dyna_start, .-new_dyna_start

/* Note: Assumes %ebx, %ebp, %esi, %edi are callee-saved */
.globl invalidate_block_eax
	.hidden invalidate_block_eax
	.type	invalidate_block_eax, @function
invalidate_block_eax:
	push	%eax
	push	%ecx
	push	%edx
	push	%eax
	jmp	invalidate_block_call
	.size	invalidate_block_eax, .-invalidate_block_eax
.globl invalidate_block_ecx
	.hidden invalidate_block_ecx
	.type	invalidate_block_ecx, @function
invalidate_block_ecx:
	push	%eax
	push	%ecx
	push	%edx
	push	%ecx
	jmp	invalidate_block_call
	.size	invalidate_block_ecx, .-invalidate_block_ecx
.globl invalidate_block_edx
	.hidden invalidate_block_edx
	.type	invalidate_block_edx, @function
invalidate_block_edx:
	push	%eax
	push	%ecx
	push	%edx
	push	%edx
	jmp	invalidate_block_call
	.size	invalidate_block_edx, .-invalidate_block_edx
.globl invalidate_block_ebx
	.hidden invalidate_block_ebx
	.type	invalidate_block_ebx, @function
invalidate_block_ebx:
	push	%eax
	push	%ecx
	push	%edx
	push	%ebx
	jmp	invalidate_block_call
	.size	invalidate_block_ebx, .-invalidate_block_ebx
.globl invalidate_block_ebp
	.hidden invalidate_block_ebp
	.type	invalidate_block_ebp, @function
invalidate_block_ebp:
	push	%eax
	push	%ecx
	push	%edx
	push	%ebp
	jmp	invalidate_block_call
	.size	invalidate_block_ebp, .-invalidate_block_ebp
.globl invalidate_block_esi
	.hidden invalidate_block_esi
	.type	invalidate_block_esi, @function
invalidate_block_esi:
	push	%eax
	push	%ecx
	push	%edx
	push	%esi
	jmp	invalidate_block_call
	.size	invalidate_block_esi, .-invalidate_block_esi
.globl invalidate_block_edi
	.hidden invalidate_block_edi
	.type	invalidate_block_edi, @function
invalidate_block_edi:
	push	%eax
	push	%ecx
	push	%edx
	push	%edi
	.size	invalidate_block_edi, .-invalidate_block_edi

	.type	invalidate_block_call, @function
invalidate_block_call:
	call	invalidate_block
	pop	%eax /* Throw away */
	pop	%edx
	pop	%ecx
	pop	%eax
	ret
	.size	invalidate_block_call, .-invalidate_block_call

.globl write_rdram_new
	.hidden write_rdram_new
	.type	write_rdram_new, @function
write_rdram_new:
	mov	address, %edi
	mov	cpu_word, %ecx
	mov	%ecx, g_rdram-0x80000000(%edi)
	jmp	.E12
	.size	write_rdram_new, .-write_rdram_new

.globl write_rdramb_new
	.hidden write_rdramb_new
	.type	write_rdramb_new, @function
write_rdramb_new:
	mov	address, %edi
	xor	$3, %edi
	movb	cpu_byte, %cl
	movb	%cl, g_rdram-0x80000000(%edi)
	jmp	.E12
	.size	write_rdramb_new, .-write_rdramb_new

.globl write_rdramh_new
	.hidden write_rdramh_new
	.type	write_rdramh_new, @function
write_rdramh_new:
	mov	address, %edi
	xor	$2, %edi
	movw	cpu_hword, %cx
	movw	%cx, g_rdram-0x80000000(%edi)
	jmp	.E12
	.size	write_rdramh_new, .-write_rdramh_new

.globl write_rdramd_new
	.hidden write_rdramd_new
	.type	write_rdramd_new, @function
write_rdramd_new:
	mov	address, %edi
	mov	cpu_dword+4, %ecx
	mov	cpu_dword, %edx
	mov	%ecx, g_rdram-0x80000000(%edi)
	mov	%edx, g_rdram-0x80000000+4(%edi)
	jmp	.E12
	.size	write_rdramd_new, .-write_rdramd_new

	.type	do_invalidate, @function
do_invalidate:
	mov	address, %edi
	mov	%edi, %ebx /* Return ebx to caller */
.E12:
	shr	$12, %edi
	cmpb	$1, invalid_code(%edi)
	je	.E13
	push	%edi
	call	invalidate_block
	pop	%edi
.E13:
	ret
	.size	do_invalidate, .-do_invalidate

.globl read_nomem_new
	.hidden read_nomem_new
	.type	read_nomem_new, @function
read_nomem_new:
	mov	address, %edi
	mov	%edi, %ebx
	shr	$12, %edi
	mov	memory_map(,%edi,4),%edi
	mov	$0x8, %eax
	test	%edi, %edi
	js	tlb_exception
	mov	(%ebx,%edi,4), %ecx
	mov	%ecx, readmem_dword
	ret
	.size	read_nomem_new, .-read_nomem_new

.globl read_nomemb_new
	.hidden read_nomemb_new
	.type	read_nomemb_new, @function
read_nomemb_new:
	mov	address, %edi
	mov	%edi, %ebx
	shr	$12, %edi
	mov	memory_map(,%edi,4),%edi
	mov	$0x8, %eax
	test	%edi, %edi
	js	tlb_exception
	xor	$3, %ebx
	movzbl	(%ebx,%edi,4), %ecx
	mov	%ecx, readmem_dword
	ret
	.size	read_nomemb_new, .-read_nomemb_new

.globl read_nomemh_new
	.hidden read_nomemh_new
	.type	read_nomemh_new, @function
read_nomemh_new:
	mov	address, %edi
	mov	%edi, %ebx
	shr	$12, %edi
	mov	memory_map(,%edi,4),%edi
	mov	$0x8, %eax
	test	%edi, %edi
	js	tlb_exception
	xor	$2, %ebx
	movzwl	(%ebx,%edi,4), %ecx
	mov	%ecx, readmem_dword
	ret
	.size	read_nomemh_new, .-read_nomemh_new

.globl read_nomemd_new
	.hidden read_nomemd_new
	.type	read_nomemd_new, @function
read_nomemd_new:
	mov	address, %edi
	mov	%edi, %ebx
	shr	$12, %edi
	mov	memory_map(,%edi,4),%edi
	mov	$0x8, %eax
	test	%edi, %edi
	js	tlb_exception
	mov	4(%ebx,%edi,4), %ecx
	mov	(%ebx,%edi,4), %edx
	mov	%ecx, readmem_dword
	mov	%edx, readmem_dword+4
	ret
	.size	read_nomemd_new, .-read_nomemd_new

.globl write_nomem_new
	.hidden write_nomem_new
	.type	write_nomem_new, @function
write_nomem_new:
	call	do_invalidate
	mov	memory_map(,%edi,4),%edi
	mov	cpu_word, %ecx
	mov	$0xc, %eax
	shl	$2, %edi
	jc	tlb_exception
	mov	%ecx, (%ebx,%edi)
	ret
	.size	write_nomem_new, .-write_nomem_new

.globl write_nomemb_new
	.hidden write_nomemb_new
	.type	write_nomemb_new, @function
write_nomemb_new:
	call	do_invalidate
	mov	memory_map(,%edi,4),%edi
	movb	cpu_byte, %cl
	mov	$0xc, %eax
	shl	$2, %edi
	jc	tlb_exception
	xor	$3, %ebx
	movb	%cl, (%ebx,%edi)
	ret
	.size	write_nomemb_new, .-write_nomemb_new

.globl write_nomemh_new
	.hidden write_nomemh_new
	.type	write_nomemh_new, @function
write_nomemh_new:
	call	do_invalidate
	mov	memory_map(,%edi,4),%edi
	movw	cpu_hword, %cx
	mov	$0xc, %eax
	shl	$2, %edi
	jc	tlb_exception
	xor	$2, %ebx
	movw	%cx, (%ebx,%edi)
	ret
	.size	write_nomemh_new, .-write_nomemh_new

.globl write_nomemd_new
	.hidden write_nomemd_new
	.type	write_nomemd_new, @function
write_nomemd_new:
	call	do_invalidate
	mov	memory_map(,%edi,4),%edi
	mov	cpu_dword+4, %edx
	mov	cpu_dword, %ecx
	mov	$0xc, %eax
	shl	$2, %edi
	jc	tlb_exception
	mov	%edx, (%ebx,%edi)
	mov	%ecx, 4(%ebx,%edi)
	ret
	.size	write_nomemd_new, .-write_nomemd_new

	.type	tlb_exception, @function
tlb_exception:
	/* eax = cause */
	/* ebx = address */
	/* ebp = instr addr + flags */
	mov	0x24(%esp), %ebp
/* Debug: 
	push	%ebp
	push	%ebx
	push	%eax
	call	tlb_debug
	pop	%eax
	pop	%ebx
	pop	%ebp
/* end debug */
	mov	g_cp0_regs+48, %esi
	mov	%ebp, %ecx
	mov	%ebp, %edx
	mov	%ebp, %edi
	shl	$31, %ebp
	shr	$12, %ecx
	or	%ebp, %eax
	sar	$29, %ebp
	and	$0xFFFFFFFC, %edx
	mov	memory_map(,%ecx,4), %ecx
	or	$2, %esi
	mov	(%edx, %ecx, 4), %ecx
	add	%ebp, %edx
	mov	%esi, g_cp0_regs+48 /* Status */
	mov	%eax, g_cp0_regs+52 /* Cause */
	mov	%edx, g_cp0_regs+56 /* EPC */
	add	$0x24, %esp
	mov	$0x6000022, %edx
	mov	%ecx, %ebp
	movswl	%cx, %eax
	shr	$26, %ecx
	shr	$21, %ebp
	sub	%eax, %ebx
	and	$0x1f, %ebp
	ror	%cl, %edx
	mov	g_cp0_regs+16, %esi
	cmovc	reg(,%ebp,8), %ebx
	and	$0xFF80000F, %esi
	mov	%ebx, reg(,%ebp,8)
	add	%ebx, %eax
	sar	$31, %ebx
	mov	%eax, g_cp0_regs+32 /* BadVAddr */
	shr	$9, %eax
	test	$2, %edi
	cmove	reg+4(,%ebp,8), %ebx
	add	$-12, %esp
	and	$0x007FFFF0, %eax
	mov	%ebx, reg+4(,%ebp,8)
	push	$0x80000180
	or	%eax, %esi
	mov	%esi, g_cp0_regs+16 /* Context */
	call	get_addr_ht
	add	$16, %esp
	movl	next_interupt, %edi
	movl	g_cp0_regs+36, %esi /* Count */
	movl	%edi, last_count
	subl	%edi, %esi
	jmp	*%eax
	.size	tlb_exception, .-tlb_exception

.globl breakpoint
	.hidden breakpoint
	.type	breakpoint, @function
breakpoint:
	.size	breakpoint, .-breakpoint
