<html>
<body>
  <div id="body" style="background-color:#ffffff;" >
<table cellspacing="0" cellpadding="0" border="0" rules="cols">
<tr class="head" style="border-bottom-width:1px;border-bottom-style:solid;" ><td class="headtd" style="padding:0;padding-top:.2em;" colspan="4">Commit in <b><tt>lxdream/src</tt></b></td></tr>
<tr><td><tt>sh4/<a href="#file1">sh4trans.h</a></tt></td><td id="added" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ddffdd;" align="right">+5</td><td></td><td class="headtd2" style="padding-left:.3em;padding-right:.3em;" nowrap="nowrap">4f02196f68eb -> 2dc47c67bb93</td></tr>
<tr class="alt" style=";" ><td><tt>   /<a href="#file2">sh4x86.in</a></tt></td><td id="addedalt" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ccf7cc;" align="right">+87</td><td id="removed" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ffdddd;" align="right">-24</td><td class="headtd2" style="padding-left:.3em;padding-right:.3em;" nowrap="nowrap">4f02196f68eb -> 2dc47c67bb93</td></tr>
<tr><td><tt>xlat/x86/<a href="#file3">x86op.h</a></tt></td><td id="added" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ddffdd;" align="right">+3</td><td></td><td class="headtd2" style="padding-left:.3em;padding-right:.3em;" nowrap="nowrap">4f02196f68eb -> 2dc47c67bb93</td></tr>
<tr class="alt" style=";" ><td><tt>xlat/<a href="#file4">xltcache.c</a></tt></td><td id="addedalt" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ccf7cc;" align="right">+15</td><td id="removed" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ffdddd;" align="right">-9</td><td class="headtd2" style="padding-left:.3em;padding-right:.3em;" nowrap="nowrap">4f02196f68eb -> 2dc47c67bb93</td></tr>
<tr><td><tt>    /<a href="#file5">xltcache.h</a></tt></td><td id="added" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ddffdd;" align="right">+1</td><td></td><td class="headtd2" style="padding-left:.3em;padding-right:.3em;" nowrap="nowrap">4f02196f68eb -> 2dc47c67bb93</td></tr>
<tr><td></td><td id="added" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ddffdd;" align="right">+111</td><td id="removed" class="headtd2" style="padding-left:.3em;padding-right:.3em; background-color:#ffdddd;" align="right">-33</td><td></td></tr>
</table>
<small id="info" style="color: #888888;" >5 modified files</small><br />
<pre class="comment" style="white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;white-space:pre-wrap;word-wrap:break-word;padding:4px;border:1px dashed #000000;background-color:#ffffdd;" >
Add support for block linking when the block target is fixed. Only a small
(~3% improvement) so far.
</pre>
<hr /><a name="file1" /><div class="file" style="border:1px solid #eeeeee;margin-top:1em;margin-bottom:1em;" >
<span class="pathname" style="font-family:monospace; float:right;" >lxdream/src/sh4</span><br />
<div class="fileheader" style="margin-bottom:.5em;" ><big><b>sh4trans.h</b></big> <small id="info" style="color: #888888;" >4f02196f68eb -> 2dc47c67bb93</small></div>
<pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >--- lxdream/src/sh4/sh4trans.h
+++ lxdream/src/sh4/sh4trans.h
@@ -154,6 +154,11 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > gboolean sh4_translate_flush_cache( void );
 
 /**
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+ * Given a block's use_list, remove all direct links to the block.
+ */
+void sh4_translate_unlink_block( void *use_list );
+
+/**
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >  * Support function called from the translator when a breakpoint is hit.
  * Either returns immediately (to skip the breakpoint), or aborts the current
  * cycle and never returns.
</pre></div>
<hr /><a name="file2" /><div class="file" style="border:1px solid #eeeeee;margin-top:1em;margin-bottom:1em;" >
<span class="pathname" style="font-family:monospace; float:right;" >lxdream/src/sh4</span><br />
<div class="fileheader" style="margin-bottom:.5em;" ><big><b>sh4x86.in</b></big> <small id="info" style="color: #888888;" >4f02196f68eb -> 2dc47c67bb93</small></div>
<pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >--- lxdream/src/sh4/sh4x86.in
+++ lxdream/src/sh4/sh4x86.in
@@ -489,9 +489,9 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > #define SLOTILLEGAL() exit_block_exc(EXC_SLOT_ILLEGAL, pc-2); sh4_x86.in_delay_slot = DELAY_NONE; return 2;
 
 /** Offset of xlat_sh4_mode field relative to the code pointer */ 
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-#define XLAT_SH4_MODE_CODE_OFFSET  (uint32_t)(offsetof(struct xlat_cache_block, xlat_sh4_mode) - offsetof(struct xlat_cache_block,code) )
-#define XLAT_CHAIN_CODE_OFFSET (uint32_t)(offsetof(struct xlat_cache_block, chain) - offsetof(struct xlat_cache_block,code) )
-#define XLAT_ACTIVE_CODE_OFFSET (uint32_t)(offsetof(struct xlat_cache_block, active) - offsetof(struct xlat_cache_block,code) )
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+#define XLAT_SH4_MODE_CODE_OFFSET  (int32_t)(offsetof(struct xlat_cache_block, xlat_sh4_mode) - offsetof(struct xlat_cache_block,code) )
+#define XLAT_CHAIN_CODE_OFFSET (int32_t)(offsetof(struct xlat_cache_block, chain) - offsetof(struct xlat_cache_block,code) )
+#define XLAT_ACTIVE_CODE_OFFSET (int32_t)(offsetof(struct xlat_cache_block, active) - offsetof(struct xlat_cache_block,code) )
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > 
 void sh4_translate_begin_block( sh4addr_t pc ) 
 {
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -511,7 +511,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >         CALL_ptr( sh4_x86.begin_callback );
     }
     if( sh4_x86.profile_blocks ) {
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-           MOVP_immptr_rptr( <span id="removedchars" style="background-color:#ff9999;font-weight:bolder;" >((uintptr_t)sh4_x86.code)</span> + XLAT_ACTIVE_CODE_OFFSET, REG_EAX );
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+     MOVP_immptr_rptr( <span id="addedchars" style="background-color:#99ff99;font-weight:bolder;" >sh4_x86.code</span> + XLAT_ACTIVE_CODE_OFFSET, REG_EAX );
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >            ADDL_imms_r32disp( 1, REG_EAX, 0 );
     }  
 }
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -575,6 +575,86 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >      JMP_TARGET(nocode); 
 }
 
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+/**
+ * 
+ */
+static void FASTCALL sh4_translate_get_code_and_backpatch( uint32_t pc )
+{
+    uint8_t *target = (uint8_t *)xlat_get_code_by_vma(pc);
+    while( target != NULL && sh4r.xlat_sh4_mode != XLAT_BLOCK_MODE(target) ) {
+        target = XLAT_BLOCK_CHAIN(target);
+       }
+    if( target == NULL ) {
+        target = sh4_translate_basic_block( pc );
+    }
+    uint8_t *backpatch = ((uint8_t *)__builtin_return_address(0)) - (CALL1_PTR_MIN_SIZE);
+    *backpatch = 0xE9;
+    *(uint32_t *)(backpatch+1) = (uint32_t)(target-backpatch)+PROLOGUE_SIZE-5;
+    *(void **)(backpatch+5) = XLAT_BLOCK_FOR_CODE(target)->use_list;
+    XLAT_BLOCK_FOR_CODE(target)->use_list = backpatch; 
+
+    uint8_t **retptr = ((uint8_t **)__builtin_frame_address(0))+1;
+    assert( *retptr == ((uint8_t *)__builtin_return_address(0)) );
+       *retptr = backpatch;
+}
+
+static void emit_translate_and_backpatch()
+{
+    /* NB: this is either 7 bytes (i386) or 12 bytes (x86-64) */
+    CALL1_ptr_r32(sh4_translate_get_code_and_backpatch, REG_ARG1);
+
+    /* When patched, the jmp instruction will be 5 bytes (either platform) -
+     * we need to reserve sizeof(void*) bytes for the use-list
+        * pointer
+        */ 
+    if( sizeof(void*) == 8 ) {
+        NOP();
+    } else {
+        NOP2();
+    }
+}
+
+/**
+ * If we're jumping to a fixed address (or at least fixed relative to the
+ * current PC, then we can do a direct branch. REG_ARG1 should contain
+ * the PC at this point.
+ */
+static void jump_next_block_fixed_pc( sh4addr_t pc )
+{
+       if( IS_IN_ICACHE(pc) ) {
+           if( sh4_x86.sh4_mode != SH4_MODE_UNKNOWN ) {
+               /* Fixed address, in cache, and fixed SH4 mode - generate a call to the
+                * fetch-and-backpatch routine, which will replace the call with a branch */
+           emit_translate_and_backpatch();              
+           return;
+               } else {
+            MOVP_moffptr_rax( xlat_get_lut_entry(GET_ICACHE_PHYS(pc)) );
+            ANDP_imms_rptr( -4, REG_EAX );
+        }
+       } else if( sh4_x86.tlb_on ) {
+        CALL1_ptr_r32(xlat_get_code_by_vma, REG_ARG1);
+    } else {
+        CALL1_ptr_r32(xlat_get_code, REG_ARG1);
+    }
+    jump_next_block();
+
+
+}
+
+void sh4_translate_unlink_block( void *use_list )
+{
+       uint8_t *tmp = xlat_output; /* In case something is active, which should never happen */
+       void *next = use_list;
+       while( next != NULL ) {
+       xlat_output = (uint8_t *)next;
+           next = *(void **)(xlat_output+5);
+               emit_translate_and_backpatch();
+       }
+       xlat_output = tmp;
+}
+
+
+
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > static void exit_block()
 {
        emit_epilogue();
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -645,16 +725,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     MOVL_r32_rbpdisp( REG_ARG1, R_PC );
     CMPL_r32_rbpdisp( REG_ECX, REG_OFFSET(event_pending) );
     JBE_label(exitloop);
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-
-    if( IS_IN_ICACHE(pc) ) {
-        MOVP_moffptr_rax( xlat_get_lut_entry(GET_ICACHE_PHYS(pc)) );
-        ANDP_imms_rptr( -4, REG_EAX );
-    } else if( sh4_x86.tlb_on ) {
-        CALL1_ptr_r32(xlat_get_code_by_vma, REG_ARG1);
-    } else {
-        CALL1_ptr_r32(xlat_get_code, REG_ARG1);
-    }
-    jump_next_block();
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+    jump_next_block_fixed_pc(pc);    
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     JMP_TARGET(exitloop);
     exit_block();
 }
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -682,16 +753,8 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >         MOVL_r32_rbpdisp( REG_ARG1, R_PC );
         CMPL_r32_rbpdisp( REG_ECX, REG_OFFSET(event_pending) );
         JBE_label(exitloop2);
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-
-        if( IS_IN_ICACHE(pc) ) {
-            MOVP_moffptr_rax( xlat_get_lut_entry(GET_ICACHE_PHYS(pc)) );
-            ANDP_imms_rptr( -4, REG_EAX );
-        } else if( sh4_x86.tlb_on ) {
-            CALL1_ptr_r32(xlat_get_code_by_vma, REG_ARG1);
-        } else {
-            CALL1_ptr_r32(xlat_get_code, REG_ARG1);
-        }
-        jump_next_block();
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+        
+        jump_next_block_fixed_pc(pc);
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >         JMP_TARGET(exitloop2);
     }
     exit_block();
</pre></div>
<hr /><a name="file3" /><div class="file" style="border:1px solid #eeeeee;margin-top:1em;margin-bottom:1em;" >
<span class="pathname" style="font-family:monospace; float:right;" >lxdream/src/xlat/x86</span><br />
<div class="fileheader" style="margin-bottom:.5em;" ><big><b>x86op.h</b></big> <small id="info" style="color: #888888;" >4f02196f68eb -> 2dc47c67bb93</small></div>
<pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >--- lxdream/src/xlat/x86/x86op.h
+++ lxdream/src/xlat/x86/x86op.h
@@ -482,6 +482,9 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > #define NEGL_rbpdisp(r1)             x86_encode_r32_rbspdisp32(0xF7, 3, disp)
 #define NEGQ_r64(r1)                 x86_encode_r64_rm64(0xF7, 3, r1)
 
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+#define NOP()                        OP(0x90)
+#define NOP2()                       OP(0x66); OP(0x90)
+
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > #define NOTB_r8(r1)                  x86_encode_r32_rm32(0xF6, 2, r1)
 #define NOTL_r32(r1)                 x86_encode_r32_rm32(0xF7, 2, r1)
 #define NOTL_rbpdisp(r1)             x86_encode_r32_rbspdisp32(0xF7, 2, disp)
</pre></div>
<hr /><a name="file4" /><div class="file" style="border:1px solid #eeeeee;margin-top:1em;margin-bottom:1em;" >
<span class="pathname" style="font-family:monospace; float:right;" >lxdream/src/xlat</span><br />
<div class="fileheader" style="margin-bottom:.5em;" ><big><b>xltcache.c</b></big> <small id="info" style="color: #888888;" >4f02196f68eb -> 2dc47c67bb93</small></div>
<pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >--- lxdream/src/xlat/xltcache.c
+++ lxdream/src/xlat/xltcache.c
@@ -22,6 +22,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > 
 #include "dreamcast.h"
 #include "sh4/sh4core.h"
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+#include "sh4/sh4trans.h"
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > #include "xlat/xltcache.h"
 #include "x86dasm/x86dasm.h"
 
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -121,6 +122,13 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     }
 }
 
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+void xlat_delete_block( xlat_cache_block_t block )
+{
+    block->active = 0;
+    *block->lut_entry = block->chain;
+    sh4_translate_unlink_block( block->use_list );
+}
+
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > static void xlat_flush_page_by_lut( void **page )
 {
     int i;
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -129,7 +137,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >             void *p = page[i];
             do {
                 xlat_cache_block_t block = XLAT_BLOCK_FOR_CODE(p);
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-                block->active = 0;
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+                xlat_delete_block(block);
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >                 p = block->chain;
             } while( p != NULL );
         }
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -377,7 +385,8 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > #else 
 void xlat_promote_to_temp_space( xlat_cache_block_t block )
 {
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-    *block->lut_entry = <span id="removedchars" style="background-color:#ff9999;font-weight:bolder;" >0</span>;
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+    *block->lut_entry = <span id="addedchars" style="background-color:#99ff99;font-weight:bolder;" >block->chain</span>;
+    xlat_delete_block(block);
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > }
 #endif
 
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -414,6 +423,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     } else {
         xlat_new_create_ptr->chain = NULL;
     }
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+    xlat_new_create_ptr->use_list = NULL;
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > 
     xlat_lut[XLAT_LUT_PAGE(address)][XLAT_LUT_ENTRY(address)] = 
         &xlat_new_create_ptr->code;
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -424,6 +434,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > 
 xlat_cache_block_t xlat_extend_block( uint32_t newSize )
 {
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+    assert( xlat_new_create_ptr->use_list == NULL );
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     while( xlat_new_create_ptr->size < newSize ) {
         if( xlat_new_cache_ptr->size == 0 ) {
             /* Migrate to the front of the cache to keep it contiguous */
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -447,6 +458,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >             xlat_new_create_ptr->size = allocation;
             xlat_new_create_ptr->lut_entry = lut_entry;
             xlat_new_create_ptr->chain = chain;
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+            xlat_new_create_ptr->use_list = NULL;
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >             *lut_entry = &xlat_new_create_ptr->code;
             memmove( xlat_new_create_ptr->code, olddata, oldsize );
         } else {
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -475,12 +487,6 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     xlat_new_cache_ptr = xlat_cut_block( xlat_new_create_ptr, destsize );
 }
 
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-void xlat_delete_block( xlat_cache_block_t block ) 
-{
-    block->active = 0;
-    *block->lut_entry = NULL;
-}
-
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" > void xlat_check_cache_integrity( xlat_cache_block_t cache, xlat_cache_block_t ptr, int size )
 {
     int foundptr = 0;
</pre><pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >@@ -517,7 +523,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >         if( page != NULL ) {
             for( j=0; j<XLAT_LUT_PAGE_ENTRIES; j++ ) {
                 void *entry = page[j];
</pre><pre id="removed" class="diff" style="margin:0; background-color:#ffdddd;" >-                if( ((uintptr_t)entry) > XLAT_LUT_ENTRY_USED ) {
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+                if( ((uintptr_t)entry) > <span id="addedchars" style="background-color:#99ff99;font-weight:bolder;" >(uintptr_t)</span>XLAT_LUT_ENTRY_USED ) {
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >                     xlat_cache_block_t block = XLAT_BLOCK_FOR_CODE(entry);
                     if( ptr >= block->code && ptr < block->code + block->size) {
                         /* Found it */
</pre></div>
<hr /><a name="file5" /><div class="file" style="border:1px solid #eeeeee;margin-top:1em;margin-bottom:1em;" >
<span class="pathname" style="font-family:monospace; float:right;" >lxdream/src/xlat</span><br />
<div class="fileheader" style="margin-bottom:.5em;" ><big><b>xltcache.h</b></big> <small id="info" style="color: #888888;" >4f02196f68eb -> 2dc47c67bb93</small></div>
<pre class="diff" style="margin:0;" ><small id="info" style="color: #888888;" >--- lxdream/src/xlat/xltcache.h
+++ lxdream/src/xlat/xltcache.h
@@ -42,6 +42,7 @@
</small></pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     uint32_t size;
     void **lut_entry; /* For deletion */
     void *chain;
</pre><pre id="added" class="diff" style="margin:0; background-color:#ddffdd;" >+    void *use_list;
</pre><pre id="context" class="diff" style="margin:0; background-color:#eeeeee;" >     uint32_t xlat_sh4_mode; /* comparison with sh4r.xlat_sh4_mode */
     uint32_t recover_table_offset; // Offset from code[0] of the recovery table;
     uint32_t recover_table_size;
</pre></div>
<center><small>Chaos Theory</small></center>
</div></body></html>