diff --git a/Chip16 program pack 04.30.2011/ROMs/Games/bruised.c16 b/Chip16 program pack 04.30.2011/ROMs/Games/bruised.c16 new file mode 100644 index 0000000..826a54a Binary files /dev/null and b/Chip16 program pack 04.30.2011/ROMs/Games/bruised.c16 differ diff --git a/Chip16 program pack 04.30.2011/ROMs/Test roms/ADSRTest.c16 b/Chip16 program pack 04.30.2011/ROMs/Test roms/ADSRTest.c16 new file mode 100644 index 0000000..8e3f262 Binary files /dev/null and b/Chip16 program pack 04.30.2011/ROMs/Test roms/ADSRTest.c16 differ diff --git a/Chip16 program pack 04.30.2011/ROMs/Test roms/BC_TestRom - Copy.c16 b/Chip16 program pack 04.30.2011/ROMs/Test roms/BC_TestRom - Copy.c16 deleted file mode 100644 index e53bb2d..0000000 Binary files a/Chip16 program pack 04.30.2011/ROMs/Test roms/BC_TestRom - Copy.c16 and /dev/null differ diff --git a/Chip16 program pack 04.30.2011/ROMs/Test roms/Chip16Spec1.3.c16 b/Chip16 program pack 04.30.2011/ROMs/Test roms/Chip16Spec1.3.c16 new file mode 100644 index 0000000..ea1972b Binary files /dev/null and b/Chip16 program pack 04.30.2011/ROMs/Test roms/Chip16Spec1.3.c16 differ diff --git a/Chip16 program pack 04.30.2011/ROMs/Test roms/adsr test.c16 b/Chip16 program pack 04.30.2011/ROMs/Test roms/adsr test.c16 deleted file mode 100644 index a83329f..0000000 Binary files a/Chip16 program pack 04.30.2011/ROMs/Test roms/adsr test.c16 and /dev/null differ diff --git a/Chip16 program pack 04.30.2011/ROMs/Test roms/flipoffscreen.c16 b/Chip16 program pack 04.30.2011/ROMs/Test roms/flipoffscreen.c16 new file mode 100644 index 0000000..ce5d18d Binary files /dev/null and b/Chip16 program pack 04.30.2011/ROMs/Test roms/flipoffscreen.c16 differ diff --git a/Chip16 program pack 04.30.2011/Sources/Bruised/arms.bin b/Chip16 program pack 04.30.2011/Sources/Bruised/arms.bin new file mode 100644 index 0000000..c5d030a Binary files /dev/null and b/Chip16 program pack 04.30.2011/Sources/Bruised/arms.bin differ diff --git a/Chip16 program pack 04.30.2011/Sources/Bruised/armsblock.bin b/Chip16 program pack 04.30.2011/Sources/Bruised/armsblock.bin new file mode 100644 index 0000000..e768d9a Binary files /dev/null and b/Chip16 program pack 04.30.2011/Sources/Bruised/armsblock.bin differ diff --git a/Chip16 program pack 04.30.2011/Sources/Bruised/armspunch.bin b/Chip16 program pack 04.30.2011/Sources/Bruised/armspunch.bin new file mode 100644 index 0000000..61b4798 Binary files /dev/null and b/Chip16 program pack 04.30.2011/Sources/Bruised/armspunch.bin differ diff --git a/Chip16 program pack 04.30.2011/Sources/Bruised/body.bin b/Chip16 program pack 04.30.2011/Sources/Bruised/body.bin new file mode 100644 index 0000000..4f49fb7 Binary files /dev/null and b/Chip16 program pack 04.30.2011/Sources/Bruised/body.bin differ diff --git a/Chip16 program pack 04.30.2011/Sources/Bruised/bruised.asm b/Chip16 program pack 04.30.2011/Sources/Bruised/bruised.asm new file mode 100644 index 0000000..571e9fc --- /dev/null +++ b/Chip16 program pack 04.30.2011/Sources/Bruised/bruised.asm @@ -0,0 +1,806 @@ +; Bruised - Fighting Game by Refraction +; +; r0 = General Purpose +; r1 = General Purpose +; r2 = General Purpose +; r3 = General Purpose +; r4 = General Purpose +; r5 = General Purpose (Random Number or Controller Destination) +; r6 = Current Sprite X-Axis / General Purpose +; r7 = Current Sprite Y-Axis / General Purpose +; r8 = Current Sprite Memory Location / General Purpose +; r9 = Player Status - 0 for nothing, 1 for walking left, 2 walking right, 4 punching, 8 kicking, 16 blocking +; ra = CPU Status - 0 for nothing, 1 for walking left, 2 walking right, 4 punching, 8 kicking, 16 blocking +; rb = Player X Position +; rc = CPU X Position +; rd = Player Health +; re = CPU Health +; rf = Fight Status - 0 for fighting, 1 is Player Won, 2 is Cpu Won. + +;Title Screen +importbin fist.bin 0 3420 spr_fist ;spr #721E +importbin logo.bin 0 4000 spr_logo ;spr #3250 +importbin font.bin 0 3072 font ;spr #0804 + +;General Ingame Sprites +importbin topbar.bin 0 2400 spr_topbar ;spr #0FA0 +importbin healthblock.bin 0 8 spr_healthblock ;spr #0801 +importbin floor.bin 0 480 spr_floor ;spr #1E10 + +;Player and CPU Character Sprites +importbin body.bin 0 306 spr_body ;spr #2209 +importbin head.bin 0 270 spr_head ;spr #1E09 +importbin legskick.bin 0 3822 spr_legskick ;spr #3127 + offset +importbin legswalk.bin 0 5733 spr_legswalk ;spr #3127 + offset +importbin stood.bin 0 1911 spr_stood ;spr #3127 +importbin arms.bin 0 714 spr_arms ;spr #2215 +importbin armspunch.bin 0 1428 spr_armspunch ;spr #2215 +importbin armsblock.bin 0 1428 spr_armsblock ;spr #2215 + +:init + ldi r9, 0 ;Player is doing nothing + ldi ra, 0 ;CPU is doing nothing + ldi rb, 20 ;put Player position on the left side of the screen + ldi rc, 242 ;put CPU position on the right hand side of the screen + ldi rd, 100 ;set player health to 100 + ldi re, 100 ;set cpu health to 100 + ldi rf, 0 ;fight isn't over, it hasn't started either! + ldi r0, 0 ;used for the flashing "PRESS START" on the menu + ldi r4, 0 ;used in the cpu "AI" + +:title_screen + cls + spr #721E ;Set the size to that of our fist + ldi r6, 20 ;X - first fist goes on the left side of the screen + ldi r7, 63 ;Y - centre it vertically + ldi r8, spr_fist ;Mem - point to our fist sprite + drw r6, r7, r8 ;r6=x, r7=y, r8=sprite memory location + ldi r6, 240 ;X - second fist goes on the right side of the screen + ldi r7, 63 ;Y - centre it vertically + flip 1, 0 ;flip the second fist so it looks like another arm ;p + drw r6, r7, r8 ;r6=x, r7=y, r8=sprite memory location + flip 0, 0 ;Set drawing back to normal + spr #3250 ;Set the size to that of our logo + ldi r6, 80 ;X - Logo goes in the middle (this is next to the first fist) + ldi r7, 70 ;Y - put it between the fists + ldi r8, spr_logo ;Mem - point to our logo sprite + drw r6, r7, r8 ;r6=x, r7=y, r8=sprite memory location + cmpi r0, 30 ;check if we should skip drawing it (every 1/2 a second) + jae skipped_start_draw ;if it's above, don't print it + ldi r6, 107 ;X - Start goes under the logo + ldi r7, 150 ;Y - put it between the fists + ldi r8, ascii_start ;Mem - point to our "Press Start" text + call draw_string ;draw the text! + +:skipped_start_draw + ldi r6, 130 ;X - Author goes in the bottom right + ldi r7, 230 ;Y - put it down the bottom + ldi r8, ascii_author ;Mem - point to our fist sprite + call draw_string ;draw the text! + vblnk + ldm r3, #FFF0 ;Load the controller state + tsti r3, #10 ;Test the Start button + jnz init_newgame ;Start the game off!! + addi r0, 1 ;Add a frame to our press start blinky counter + cmpi r0, 60 ;we want to reset it on 60, so we might as well jump to the init + jz init ;if we've done 60 frames, start it again + jmp title_screen ;otherwise loop around + +:init_newgame + cls + call draw_elements + ldi r0, 0 ;prep a temp reg to count frames + ldi r6, 107 ;X - Start goes under the logo + ldi r7, 100 ;Y - put it between the fists + ldi r8, ascii_getready ;Mem - point to our get ready text + call draw_string ;draw the text! + ;call wait_two_seconds ;wait the 2 seconds + cls + call draw_elements + ldi r0, 0 ;prep a temp reg to count frames + ldi r6, 130 ;X - Start goes under the logo + ldi r7, 100 ;Y - put it between the fists + ldi r8, ascii_fight ;Mem - point to our get ready text + call draw_string ;draw the text! + ;call wait_two_seconds ;wait the 2 seconds + +:game_loop + cls + call cpu_check_elements + call check_controls + call check_punch + call check_kick + call draw_elements + call check_health + vblnk + cmpi rf, 0 + jnz game_finished + jmp game_loop + +:game_finished + cmpi rf, 1 + jnz cpu_win + jmp player_win + +:cpu_win + cls + call draw_elements + ldi r0, 0 ;prep a temp reg to count frames + ldi r6, 107 ;X - Start goes under the logo + ldi r7, 70 ;Y - put it between the fists + ldi r8, ascii_cpuwin ;Mem - point to our get ready text + call draw_string ;draw the text! + call wait_two_seconds ;wait the 2 seconds + jmp init + +:player_win + cls + call draw_elements + ldi r0, 0 ;prep a temp reg to count frames + ldi r6, 107 ;X - Start goes under the logo + ldi r7, 70 ;Y - put it between the fists + ldi r8, ascii_playerwin ;Mem - point to our get ready text + call draw_string ;draw the text! + call wait_two_seconds ;wait the 2 seconds + jmp init + +:check_health + cmpi re, 0 + jnz check_player + ldi rf, 1 +:check_player + cmpi rd, 0 + jnz returnsub + ldi rf, 2 + ret + +:draw_elements + call draw_topbar + call draw_player_health + call draw_cpu_health + call draw_floor + call draw_player + call draw_computer + ret + +;*****************************CONTROLLER STUFF********************** +:check_controls + andi r9, #1c ;set ourselves as not walking + ldm r3, #FFF0 ;Load the controller state + cmpi r3, #C0 + jz player_blocking + tsti r3, #8 ;Test the Right button + jnz move_right + tsti r3, #8 ;Test the Right button + jnz move_right + tsti r3, #4 ;Test the Left button + jnz move_left + andi r9, #c + ret + +:move_right + cmpi r9, 4 + jae returnsub + ldi r9, 2 ;set as walking right + mov r0, rc ;find the cpu position + mov r1, rb ;grab our current position + subi r0, 35 + cmp r1, r0 + jae returnsub + addi rb, 1 + ret +:move_left + cmpi r9, 4 + jae returnsub + ldi r9, 1 ;set as walking left + cmpi rb, 20 + jz returnsub + subi rb, 1 + ret + +:player_blocking + cmpi r9, 4 + jnz returnsub + ldi r0, 1 + stm r0, player_frame + ldi r9, 16 ;set as blocking + ret + +:check_punch + tsti r3, #40 ;Test the A button for punching + jnz player_punch + call clear_player_punch + ret +:check_kick + tsti r3, #80 ;Test the B button for punching + jnz player_kick + call clear_player_kick + ret + +:clear_player_punch + cmpi r9, 4 + jnz returnsub + ldm r0, player_frame + cmpi r0, 9 + jnz returnsub + ldi r0, 0 + ldi r9, 0 + stm r0, player_frame + ret + +:player_punch + cmpi r9, 4 + jae returnsub + ldi r9, 4 ;set as punching + ldi r0, 1 + stm r0, player_frame + cmpi ra, 16 ;see if cpu is blocking + jz returnsub + mov r0, rc ;find the cpu position + mov r1, rb ;grab our current position + subi r0, 45 + cmp r0, r1 + jae returnsub + subi re, 2 ;reduce cpu health + ret + +:clear_player_kick + cmpi r9, 8 + jnz returnsub + ldm r0, player_frame + cmpi r0, 9 + jnz returnsub + ldi r0, 0 + ldi r9, 0 + stm r0, player_frame + ret + +:player_kick + cmpi r9, 4 + jae returnsub + ldi r9, 8 ;set as kicking + ldi r0, 1 + stm r0, player_frame + cmpi ra, 16 ;see if cpu is blocking + jz returnsub + mov r0, rc ;find the cpu position + mov r1, rb ;grab our current position + subi r0, 45 + cmp r0, r1 + jae returnsub + subi re, 2 ;reduce cpu health + ret + +;********************PLAYER STUFF*************************************** +:draw_player + call draw_playerlegs + call draw_playerheadbody + call draw_playerarms + ret + +:draw_playerlegs + spr #3127 + + cmpi r9, 8 + jnz draw_normallegs + jmp draw_player_kick +:draw_normallegs + tsti r9, 3 + jz playerstood +:playerwalking + ldi r8, spr_legswalk ;start with our legs + ldm r0, player_frame + cmpi r9, 2 + jnz playerwalkingleft +:playerwalkingright + addi r0, 1 + andi r0, #1f + cmpi r0, #1b + jnz store_legs_frame + ldi r0, 0 + jmp store_legs_frame +:playerwalkingleft + cmpi r9, 1 + jnz playerstood + subi r0, 1 + andi r0, #1f + cmpi r0, #1f + jnz store_legs_frame + ldi r0, #1a + jmp store_legs_frame +:playerstood + ldi r8, spr_stood ;start with our legs + ldi r0, 0 + jmp draw_playerlegs_end +:store_legs_frame + stm r0, player_frame +:draw_playerlegs_end + + divi r0, 9 + muli r0, 1911 ;point to correct frame + add r8, r0 + mov r6, rb ;copy our player x position + ldi r7, 161 ;top of the legs plus the floor + drw r6, r7, r8 ;r6=x, r7=y, r8=sprite memory location + ret + +:draw_player_kick + ldi r8, spr_legskick + ldm r0, player_frame + cmpi r0, 9 + jz playerstood + mov r1, r0 + addi r0, 1 + subi r1, 1 + divi r1, 3 + andi r1, 1 + muli r1, 1911 ;point to correct frame + add r8, r1 + mov r6, rb ;copy our player x position + ldi r7, 161 ;top of the legs plus the floor + drw r6, r7, r8 ;r6=x, r7=y, r8=sprite memory location + stm r0, player_frame + ret + +:draw_playerheadbody + spr #2209 ;body + ldi r8, spr_body ;start with our legs + mov r6, rb ;copy our player x position + addi r6, 30 + ldi r7, 127 ;top of the legs plus the floor + drw r6, r7, r8 ;r6=x, r7=y, r8=sprite memory location + spr #1E09 ;head + ldi r8, spr_head ;start with our legs + mov r6, rb ;copy our player x position + addi r6, 32 + ldi r7, 97 ;top of the legs plus the floor + drw r6, r7, r8 ;r6=x, r7=y, r8=sprite memory location + ret + +:draw_playerarms + cmpi r9, 4 + jnz draw_playertestblockarms + jmp draw_player_punch +:draw_playertestblockarms + cmpi r9, 16 + jnz draw_normalarms + jmp draw_player_block +:draw_normalarms + spr #2215 + ldi r8, spr_arms +:draw_arms_routine + mov r6, rb ;copy our player x position + addi r6, 32 + ldi r7, 127 ;top of the legs plus the floor + drw r6, r7, r8 ;r6=x, r7=y, r8=sprite memory location + ret + +:draw_player_block + spr #2215 + ldi r8, spr_armsblock + ldm r0, player_frame + cmpi r0, 6 + jz draw_arms_routine + mov r1, r0 + addi r0, 1 + subi r1, 1 + divi r1, 3 + andi r1, 1 + muli r1, 714 + add r8, r1 + cmpi r0, 6 + jz draw_arms_routine + mov r6, rb ;copy our player x position + addi r6, 32 + ldi r7, 127 ;top of the legs plus the floor + drw r6, r7, r8 ;r6=x, r7=y, r8=sprite memory location + stm r0, player_frame + ret + +:draw_player_punch + spr #2215 + ldi r8, spr_armspunch + ldm r0, player_frame + cmpi r0, 9 + jz draw_normalarms + mov r1, r0 + addi r0, 1 + subi r1, 1 + divi r1, 3 + andi r1, 1 + muli r1, 714 + add r8, r1 + mov r6, rb ;copy our player x position + addi r6, 34 + ldi r7, 127 ;top of the legs plus the floor + drw r6, r7, r8 ;r6=x, r7=y, r8=sprite memory location + stm r0, player_frame + ret + +;*****************************CPU AI STUFF************************** +:cpu_check_elements + mov r0, rc ;find the cpu position + mov r1, rb ;grab our current position + subi r0, 45 + cmp r0, r1 + jc cpu_check_elements_nexttoplayer + cmpi r4, 0 + ja cpu_process + andi ra, #c + rnd r4, 30 ;pick a random number of frames to do something for. + rnd r5, 4 ;generate a number between 0-4 + jmp cpu_check_elements +cpu_process: + subi r4, 1 + cmpi r5, 2 + jae cpu_move_left + cmpi r5, 0 + jz cpu_move_right + ret + +:cpu_check_elements_nexttoplayer + cmpi r4, 0 + ja cpu_process_attacks + andi ra, #1c + rnd r4, 10 ;pick a random number of frames to do something for. + rnd r5, 4 ;generate a number between 0-4 + jmp cpu_check_elements_nexttoplayer +cpu_process_attacks: + subi r4, 1 + cmpi r5, 2 + jz cpu_kick + call clear_cpu_kick + cmpi r5, 3 + jz cpu_punch + call clear_cpu_punch + cmpi r5, 4 + jae cpu_block + andi ra, #c + ret + +:cpu_block + cmpi ra, 4 + jae returnsub + cmpi ra, 8 + jz returnsub + ldi ra, 16 ;set as blocking + ret + +:clear_cpu_punch + cmpi ra, 4 + jnz returnsub + ldm r0, cpu_frame + cmpi r0, 9 + jnz returnsub + ldi r0, 0 + ldi ra, 0 + stm r0, cpu_frame + ret + +:cpu_punch + cmpi ra, 4 + jae returnsub + ldi r4, 9 + ldi ra, 4 ;set as punching + ldi r0, 1 + stm r0, cpu_frame + mov r0, rc ;find the cpu position + mov r1, rb ;grab our current position + subi r0, 45 + cmp r0, r1 + jae returnsub + cmpi r9, 16 ;see if player is blocking + jnz reduce_p_health + addi r4, 20 + ldi r5, 3 ;stop the cpu attacking a moment + ret + +:reduce_p_health + subi rd, 2 ;reduce player health + ret + +:cpu_move_right + cmpi ra, 4 + jae returnsub + ldi ra, 2 ;set as walking right + cmpi rc, 242 + jz returnsub + addi rc, 1 + ret + +:cpu_move_left + cmpi ra, 4 + jae returnsub + ldi ra, 1 ;set as walking left + mov r0, rc ;find the cpu position + mov r1, rb ;grab our current position + subi r0, 35 + cmp r1, r0 + jae returnsub + subi rc, 1 + ret + +:clear_cpu_kick + cmpi ra, 8 + jnz returnsub + ldm r0, cpu_frame + cmpi r0, 9 + jnz returnsub + ldi r0, 0 + ldi ra, 0 + stm r0, cpu_frame + ret + +:cpu_kick + cmpi ra, 4 + jae returnsub + ldi r4, 9 + ldi ra, 8 ;set as kicking + ldi r0, 1 + stm r0, cpu_frame + mov r0, rc ;find the cpu position + mov r1, rb ;grab our current position + subi r0, 45 + cmp r0, r1 + jae returnsub + cmpi r9, 16 ;see if player is blocking + jnz reduce_p_health + addi r4, 20 + ldi r5, 3 ;stop the cpu attacking a moment + ret + +;********************CPU STUFF*************************************** +:draw_computer + flip 1, 0 + call draw_cpulegs + call draw_cpuheadbody + call draw_cpuarms + flip 0, 0 + ret + +:draw_cpulegs + spr #3127 + + cmpi ra, 8 + jnz draw_normalcpulegs + jmp draw_cpu_kick +:draw_normalcpulegs + tsti ra, 3 + jz cpustood +:cpuwalking + ldi r8, spr_legswalk ;start with our legs + ldm r0, cpu_frame + cmpi ra, 2 + jnz cpuwalkingleft +:cpuwalkingright + subi r0, 1 + andi r0, #1f + cmpi r0, #1f + jnz store_cpulegs_frame + ldi r0, #1a + jmp store_cpulegs_frame +:cpuwalkingleft + cmpi ra, 1 + jnz cpustood + addi r0, 1 + andi r0, #1f + cmpi r0, #1b + jnz store_cpulegs_frame + ldi r0, 0 + jmp store_cpulegs_frame +:cpustood + ldi r8, spr_stood ;start with our legs + ldi r0, 0 + jmp draw_cpulegs_end +:store_cpulegs_frame + stm r0, cpu_frame +:draw_cpulegs_end + + divi r0, 9 + muli r0, 1911 ;point to correct frame + add r8, r0 + mov r6, rc ;copy our CPU x position + ldi r7, 161 ;top of the legs plus the floor + drw r6, r7, r8 ;r6=x, r7=y, r8=sprite memory location + ret + +:draw_cpu_kick + ldi r8, spr_legskick + ldm r0, cpu_frame + cmpi r0, 9 + jz cpustood + mov r1, r0 + addi r0, 1 + subi r1, 1 + divi r1, 3 + andi r1, 1 + muli r1, 1911 ;point to correct frame + add r8, r1 + mov r6, rc ;copy our player x position + ldi r7, 161 ;top of the legs plus the floor + drw r6, r7, r8 ;r6=x, r7=y, r8=sprite memory location + stm r0, cpu_frame + ret + +:draw_cpuheadbody + spr #2209 ;body + ldi r8, spr_body ;start with our legs + mov r6, rc ;copy our cpu x position + addi r6, 30 + ldi r7, 127 ;top of the legs plus the floor + drw r6, r7, r8 ;r6=x, r7=y, r8=sprite memory location + spr #1E09 ;head + ldi r8, spr_head ;start with our legs + mov r6, rc ;copy our cpu x position + addi r6, 28 + ldi r7, 97 ;top of the legs plus the floor + drw r6, r7, r8 ;r6=x, r7=y, r8=sprite memory location + ret + +:draw_cpuarms + cmpi ra, 4 + jnz draw_cputestblockarms + jmp draw_cpu_punch +:draw_cputestblockarms + cmpi ra, 16 + jnz draw_cpunormalarms + jmp draw_cpu_block +:draw_cpunormalarms + spr #2215 + ldi r8, spr_arms +:draw_cpuarms_routine + mov r6, rc ;copy our cpu x position + addi r6, 3 + ldi r7, 127 ;top of the legs plus the floor + drw r6, r7, r8 ;r6=x, r7=y, r8=sprite memory location + ret + +:draw_cpu_block + spr #2215 + ldi r8, spr_armsblock + ldm r0, cpu_frame + cmpi r0, 6 + jz draw_cpuarms_routine + mov r1, r0 + addi r0, 1 + subi r1, 1 + divi r1, 3 + andi r1, 1 + muli r1, 714 + add r8, r1 + cmpi r0, 6 + jz draw_cpuarms_routine + mov r6, rc ;copy our cpu x position + addi r6, 3 + ldi r7, 127 ;top of the legs plus the floor + drw r6, r7, r8 ;r6=x, r7=y, r8=sprite memory location + stm r0, cpu_frame + ret + +:draw_cpu_punch + spr #2215 + ldi r8, spr_armspunch + ldm r0, cpu_frame + cmpi r0, 9 + jz draw_cpunormalarms + mov r1, r0 + addi r0, 1 + subi r1, 1 + divi r1, 3 + andi r1, 1 + muli r1, 714 + add r8, r1 + mov r6, rc ;copy our cpu x position + addi r6, 2 + ldi r7, 127 ;top of the legs plus the floor + drw r6, r7, r8 ;r6=x, r7=y, r8=sprite memory location + stm r0, cpu_frame + ret + +;********************HUD STUFF*************************************** +:wait_two_seconds + addi r0, 1 ;add one frame to our counter + vblnk + cmpi r0, 120 ;wait for 120 frames + jnz wait_two_seconds + ret + +:draw_topbar + spr #0FA0 ;size of the top bar + ldi r6, 0 ;X - Top bar is the full length + ldi r7, 0 ;Y - Stick it at the top + ldi r8, spr_topbar ;Mem - point to our topbar sprite + drw r6, r7, r8 ;r6=x, r7=y, r8=sprite memory location + ret + +:draw_floor + spr #1E10 ;size of the floor + ldi r6, 0 ;X - Start from the far left + ldi r7, 210 ;Y - Stick it at the bottom - sprite height (30) + ldi r8, spr_floor ;Mem - point to our floor sprite +:draw_floor_loop + drw r6, r7, r8 ;r6=x, r7=y, r8=sprite memory location + addi r6, 32 ;move over the width of our sprite + cmpi r6, 320 ;see if we've hit the screen edge + jz returnsub ;we have so exit + jmp draw_floor_loop ;we still have space to draw so keep looping + +:draw_player_health + ldi r6, 9 ;X - Start from the far left + ldi r7, 4 ;Y - Stick it at the bottom - sprite height (30) + mov r0, rd ;Copy the players health to a temporary reg for looping + jmp draw_health_blocks + +:draw_cpu_health + ldi r6, 311 ;X - Start from the far left + sub r6, re ;take off the health so it starts in the right place + ldi r7, 4 ;Y - Stick it at the bottom - sprite height (30) + mov r0, re ;Copy the CPUs health to a temporary reg for looping + jmp draw_health_blocks + +:draw_health_blocks + spr #0801 + ldi r8, spr_healthblock ;Mem - point to our floor sprite +:draw_health_blocks_loop + cmpi r0, 0 ;see if its gone out of the bar + jz returnsub ;it hasn't so keep drawing! + drw r6, r7, r8 ;r6=x, r7=y, r8=sprite memory location + subi r0, 2 ;move over the width of our health sprite (2) + addi r6, 2 ;move the X over to the next position + jmp draw_health_blocks_loop + + +;Stolen and modified from Shendo's Music Maker +:draw_string ;Draw string on screen + spr #0804 ;Set 8x8 pixel sprites + ldm r1, r8 ;Load character from memory + andi r1, #FF ;Only the lo byte is needed + + cmpi r1, 255 ;Remove terminator + jz returnsub ;Terminator reached, break subroutine + + subi r1, 32 + muli r1, 32 ;Each character is 32 bytes long + addi r1, font ;Apply offset to font address + + drw r6, r7, r1 ;Draw 8x8 character on the set coordinates + + addi r8, 1 ;Increase memory offset + addi r6, 9 ;Increase X coordinate + + jmp draw_string ;loop around, we have text left! + +:returnsub + ret + +:ascii_start + db "PRESS START" + db 255 + +:ascii_author + db "Written by Refraction" + db 255 + +:ascii_getready + db "Get Ready..." + db 255 + +:ascii_fight + db "Fight!" + db 255 + +:ascii_playerwin + db "Player wins!" + db 255 + +:ascii_cpuwin + db "CPU wins!" + db 255 + +:player_frame + db #00 + db #00 + +:cpu_frame + db #00 + db #00 \ No newline at end of file diff --git a/Chip16 program pack 04.30.2011/Sources/Bruised/colorblock.bin b/Chip16 program pack 04.30.2011/Sources/Bruised/colorblock.bin new file mode 100644 index 0000000..c76ac42 Binary files /dev/null and b/Chip16 program pack 04.30.2011/Sources/Bruised/colorblock.bin differ diff --git a/Chip16 program pack 04.30.2011/Sources/Bruised/fist.bin b/Chip16 program pack 04.30.2011/Sources/Bruised/fist.bin new file mode 100644 index 0000000..7a7fb00 Binary files /dev/null and b/Chip16 program pack 04.30.2011/Sources/Bruised/fist.bin differ diff --git a/Chip16 program pack 04.30.2011/Sources/Bruised/floor.bin b/Chip16 program pack 04.30.2011/Sources/Bruised/floor.bin new file mode 100644 index 0000000..c3fd779 --- /dev/null +++ b/Chip16 program pack 04.30.2011/Sources/Bruised/floor.bin @@ -0,0 +1 @@ +".""â"""""""ââ""""î..î"â"..."""â.""â"â.".""â""â".î""".â"â"""""""""".""â"""ââ"ââ"â"â.â".."""""â.î"""""""â.""â""".""â"ââ"â"â".""""""""â"".â.."."â."â""""â."ââ""""â""..""."î"â""""âî."."."ââ."""""î."î"."..î.â.".î"""""â""""""""â"""â"â".""""""".."""."."î.â"î"â".â"â"â"""â".""""â"""""â"""""""""."â"â"""""""."""âââ""".â".""î"î.î""""."â"""î"âââ"""""".â"."""".î"""î"â..""â".""""î.â""î""""â"."""""â"".î"".â""""â""ââ""â.â."""".."."â""".."""."""î"""â"â.âî".â.""î"".ââîâ.""âââ"".".""""â""â""."." \ No newline at end of file diff --git a/Chip16 program pack 04.30.2011/Sources/Bruised/font.bin b/Chip16 program pack 04.30.2011/Sources/Bruised/font.bin new file mode 100644 index 0000000..dd33b37 Binary files /dev/null and b/Chip16 program pack 04.30.2011/Sources/Bruised/font.bin differ diff --git a/Chip16 program pack 04.30.2011/Sources/Bruised/head.bin b/Chip16 program pack 04.30.2011/Sources/Bruised/head.bin new file mode 100644 index 0000000..48225a3 Binary files /dev/null and b/Chip16 program pack 04.30.2011/Sources/Bruised/head.bin differ diff --git a/Chip16 program pack 04.30.2011/Sources/Bruised/healthblock.bin b/Chip16 program pack 04.30.2011/Sources/Bruised/healthblock.bin new file mode 100644 index 0000000..5f42cbd --- /dev/null +++ b/Chip16 program pack 04.30.2011/Sources/Bruised/healthblock.bin @@ -0,0 +1 @@ +33333333 \ No newline at end of file diff --git a/Chip16 program pack 04.30.2011/Sources/Bruised/legskick.bin b/Chip16 program pack 04.30.2011/Sources/Bruised/legskick.bin new file mode 100644 index 0000000..816ed55 Binary files /dev/null and b/Chip16 program pack 04.30.2011/Sources/Bruised/legskick.bin differ diff --git a/Chip16 program pack 04.30.2011/Sources/Bruised/legswalk.bin b/Chip16 program pack 04.30.2011/Sources/Bruised/legswalk.bin new file mode 100644 index 0000000..b5c241f Binary files /dev/null and b/Chip16 program pack 04.30.2011/Sources/Bruised/legswalk.bin differ diff --git a/Chip16 program pack 04.30.2011/Sources/Bruised/logo.bin b/Chip16 program pack 04.30.2011/Sources/Bruised/logo.bin new file mode 100644 index 0000000..c122edf Binary files /dev/null and b/Chip16 program pack 04.30.2011/Sources/Bruised/logo.bin differ diff --git a/Chip16 program pack 04.30.2011/Sources/Bruised/stood.bin b/Chip16 program pack 04.30.2011/Sources/Bruised/stood.bin new file mode 100644 index 0000000..9b44216 Binary files /dev/null and b/Chip16 program pack 04.30.2011/Sources/Bruised/stood.bin differ diff --git a/Chip16 program pack 04.30.2011/Sources/Bruised/topbar.bin b/Chip16 program pack 04.30.2011/Sources/Bruised/topbar.bin new file mode 100644 index 0000000..e598057 Binary files /dev/null and b/Chip16 program pack 04.30.2011/Sources/Bruised/topbar.bin differ diff --git a/Chip16 program pack 04.30.2011/Sources/Chip16Spec1.3.asm b/Chip16 program pack 04.30.2011/Sources/Chip16Spec1.3.asm new file mode 100644 index 0000000..c7602fc --- /dev/null +++ b/Chip16 program pack 04.30.2011/Sources/Chip16Spec1.3.asm @@ -0,0 +1,240 @@ +; Chip16 v1.3 Specification Test - Chip1613ST +; Tests only new opcodes: MOD,REM,NOT,NEG +FontSize equ $0804 ; 8 x 8 pixel +FontWidth equ 8 +FontHeight equ 8 +ScreenWidth equ 320 +ScreenHeight equ 240 + +; R6 = Current Opcode Test +; R7 = Current address of char Cursor +Main: + call SetN + call UnsetN + ldi R7, StartOSD + addi R7, 53 + call DrawChars + +; Test Ax - Division extensions, MOD, REM +TEST_1: + call IncreaseTestNumber +; A3 - MOD RX, HHLL + ldi R0, 31313 + modi R0, 13 ;=> R0=9 + cmpi R0, 9 + jnz WriteFailedCurrentTest +TEST_2: + call IncreaseTestNumber +; A4 - MOD RX, RY + ldi R0, -31313 + ldi R1, 13 + mod R0, R1 ;=> R0=9 + cmpi R0, 9 + jnz WriteFailedCurrentTest +TEST_3: + call IncreaseTestNumber +; A5 - MOD RX, RY, RZ + ldi R0, 0 + ldi R1, -31313 + ldi R2, -13 + mod R0,R1,R2 ;=> R0=9 + cmpi R0, 9 + jnz WriteFailedCurrentTest +TEST_4: + call IncreaseTestNumber +; A6 - REM RX, HHLL + ldi R0, -12345 + remi R0, 45 ;=> R0=-15 + cmpi R0, -15 + jnz WriteFailedCurrentTest +TEST_5: + call IncreaseTestNumber +; A7 - REM RX, RY + ldi R0, 31999 + ldi R1, -45 + rem R0,R1 ;=> R0=4 + cmpi R0, 4 + jnz WriteFailedCurrentTest +TEST_6: + call IncreaseTestNumber +; A8 - REM RX, RY, RZ + ldi R1, -23456 + ldi R2, -57 + rem R0,R1,R2 ;=> R0=-29 + cmpi R0, -29 + jnz WriteFailedCurrentTest +; Test Ex - Not/Neg +TEST_7: + call IncreaseTestNumber +; E0 - NOT RX, HHLL + noti R0, 0x1234 + cmpi R0, 0xEDCB + jnz WriteFailedCurrentTest +TEST_8: + call IncreaseTestNumber +; E1 - NOT RX + ldi R0, 0x4567 + not R0 + cmpi R0, 0xBA98 + jnz WriteFailedCurrentTest +TEST_9: + call IncreaseTestNumber +; E2 - NOT RX, RY + ldi R1, 0xAFAF + not R0, R1 + cmpi R0, 0x5050 + jnz WriteFailedCurrentTest +TEST_10: + call IncreaseTestNumber +; E3 - NEG RX, HHLL + negi R0, 4660 + cmpi R0, -4660 + jnz WriteFailedCurrentTest +TEST_11: +; E4 - NEG RX + call IncreaseTestNumber + ldi R0, -32123 + neg R0 + cmpi R0, 32123 + jnz WriteFailedCurrentTest +TEST_12: + call IncreaseTestNumber +; E5 - NEG RX, RY + ldi R1, 32767 + neg R0, R1 + cmpi R0, -32767 + jnz WriteFailedCurrentTest + + call WriteALLTESTSOK + call DrawChars +Loop: + jmp Loop + +; Draw Chars +DrawChars: + pushall +OSDInit: + pal Palette + spr FontSize ; set sprite size to 8x8 + ldi R0, StartOSD + ldi R1, ScreenWidth + ldi R2, MarioFont + addi R2, 3 ; skip 3 byte header + ldi R3, 0 + ldi R4, 0 +OSDDrawLoop: + ldm R5, R0 + andi R5, 0xFF + cmpi R5, 0x20 ;space handled seperately + jnz NoSpace + addi R5, 0x20 ;0x20+0x20-0x30 = 0x10 (space) +NoSpace: + subi R5, 0x30 + shl R5, 5 + add R5, R2 + drw R3, R4, R5 + addi R0, 1 + addi R3, FontWidth + cmpi R3, 320 + jnz OSDDrawLoop + ldi R3, 0 + addi R4, 8 + cmpi R4, 16 + jnz OSDDrawLoop + popall + ret + +WriteFailedCurrentTest: + call WriteFAILED + call WriteCurrentNumber + call DrawChars +LoopError: + jmp LoopError + +; Write ALL TESTS OK +WriteALLTESTSOK: + ldi R0, AllTestsOk + call WriteString + ret +; Write FAILED +WriteFAILED: + ldi R0, FAILED + call WriteString + ret + +; Write Current Number +WriteCurrentNumber: + ldi R0, CurrentTest + call WriteString + ret + +; Write string starting at R0 +; at addr in R7 +WriteString: + call ReadByte + ;check of ending @, end if found! + cmpi R1, 0x40 ; ASCII of @ + jz WriteStringEnd + push R0 ; store source addr on stack + mov R0, R7 + call WriteByte + pop R0 ; restore source addr from stack + addi R7, 1 + addi R0, 1 + jp WriteString +WriteStringEnd: + ret + +; Increase ASCII-BCD 2 byte number, works for (00-99) +IncreaseTestNumber: + ;push R2 + ldi R0, CurrentTest + addi R0, 1 + ;ldm R0, R2 + call ReadByte + addi R1, 1 + cmpi R1, 0x3A + jnz WriteBCD0Back + ldi R1, 0x30 + ;stm R0, R2 + call WriteByte + subi R0, 1 + ;ldm R0, R2 ; read BCD1 + call ReadByte + addi R1, 1 + call WriteByte + ;stm R0, R2 + jp EndIncreaseTestNumber +WriteBCD0Back: + ;stm R0, R2 + call WriteByte +EndIncreaseTestNumber: + ;pop R2 + ret +include ByteAccessLib.asm +include ManipulateFlagsLib.asm +EndOfProgram: +db 0x00 + +StartOSD: ; A=16(0x10) +db " CHIP16 V1" +db 0x3D +db "3 SPECIFICATION TEST " +db " " +EndOSD: +db 0x00 +CurrentTest: ; written in ASCII BCD +db 0x30, 0x30 +db "@" +; strings +FAILED: +db "FAILED TEST @" +AllTestsOk: +db " (CHAR-0x30) +importbin C:\Share\Chip16\tchip16_1.4.5\Mario\MarioFontLong.bmp.bin 0 1539 MarioFont diff --git a/Chip16 program pack 04.30.2011/Sources/flipoffscreen.asm b/Chip16 program pack 04.30.2011/Sources/flipoffscreen.asm new file mode 100644 index 0000000..0b1327c --- /dev/null +++ b/Chip16 program pack 04.30.2011/Sources/flipoffscreen.asm @@ -0,0 +1,174 @@ +; Flip & Offscreen test by Refraction +; +; r0 = General Purpose +; r1 = General Purpose +; r2 = Flipped Horizontal Status +; r3 = Flipped Vertical Status +; r4 = Current Controller State +; r5 = Last Controller State +; r6 = Sprite Draw X pos +; r7 = Sprite Draw Y pos +; r8 = Sprite Memory Location/Ascii memory +; r9 = General Purpose +; ra = Box X position +; rb = Box Y position +; rc = General Purpose +; rd = General Purpose +; re = General Purpose +; rf = General Purpose + +importbin font.bin 0 3072 font ;spr #0804 +importbin colorblock.bin 0 5000 box ;spr #6432 + +:init + ldi ra, 50 + ldi rb, 50 ;start our box in the top left + +:check_controls + cls + call testflips + ldm r4, #FFF0 ;Load the controller state + andi r4, #C0 ;just a and b + xor r4, r5 ;see if the state actually changed + cmpi r4, 0 ;see if the state has changed + jz check_movement + ldm r5, #FFF0 ;state has changed so regrab it + and r5, r4 ;make sure we only process what's changed +:test_a + tsti r5, #40 ;Test the A button + jz test_b + xori r3, 1 ;flip the vertical flip +:test_b + tsti r5, #80 ;Test the B button + jz check_movement + xori r2, 1 ;flip the horizontal flip +:check_movement + ldm r4, #FFF0 ;Load the controller state + call move_up + call move_down + call move_left + call move_right + +:draw_box + spr #6432 + ldi r8, box + drw ra, rb, r8 + +:draw_text + flip 0, 0 ;make sure we arent flipped for text + ldi r8, ascii_fliphoz ;draw our title text + ldi r6, 0 ; X = 100 + ldi r7, 230 ; Y = 0 + call draw_string + cmpi r2, 1 + jz htext_enabled + ldi r8, ascii_disabled +:continue_draw_text + call draw_string + ldi r8, ascii_flipvert ;draw our title text + ldi r6, 0 ; X = 100 + ldi r7, 220 ; Y = 0 + call draw_string + cmpi r3, 1 + jz vtext_enabled + ldi r8, ascii_disabled +:continue_draw_text2 + call draw_string + +:end_wait + vblnk + jmp check_controls + +:move_up + tsti r4, #1 ;Check up + jz returnsub + subi rb, 1 + ret +:move_down + tsti r4, #2 ;Check down + jz returnsub + addi rb, 1 + ret +:move_left + tsti r4, #4 ;Check left + jz returnsub + subi ra, 1 + ret +:move_right + tsti r4, #8 ;Check right + jz returnsub + addi ra, 1 + ret + +:testflips + tst r2, r3 + jnz flip_h1v1 + tsti r2, 1 + jnz flip_h1v0 + tsti r3, 1 + jnz flip_h0v1 + jmp flip_h0v0 + +:flip_h0v0 + flip 0, 0 + ret +:flip_h1v0 + flip 1, 0 + ret +:flip_h0v1 + flip 0, 1 + ret +:flip_h1v1 + flip 1, 1 + ret + +:htext_enabled + ldi r8, ascii_enabled + jmp continue_draw_text + +:vtext_enabled + ldi r8, ascii_enabled + jmp continue_draw_text2 + +;Stolen and modified from Shendo's Music Maker +:draw_string ;Draw string on screen + spr #0804 ;Set 8x8 pixel sprites + ldm r1, r8 ;Load character from memory + andi r1, #FF ;Only the lo byte is needed + + cmpi r1, 255 ;Remove terminator + jz returnsub ;Terminator reached, break subroutine + + subi r1, 32 + muli r1, 32 ;Each character is 32 bytes long + addi r1, font ;Apply offset to font address + + drw r6, r7, r1 ;Draw 8x8 character on the set coordinates + + addi r8, 1 ;Increase memory offset + addi r6, 9 ;Increase X coordinate + + jmp draw_string ;loop around, we have text left! + +:returnsub + ret + +:ascii_fliphoz + db "(B) Horizontal Flip is " + db 255 + +:ascii_flipvert + db "(A) Vertical Flip is " + db 255 + +:ascii_enabled + db "enabled" + db 255 + +:ascii_disabled + db "disabled" + db 255 + +:ascii_title + db "Flip and offscreen sprite test by Refraction" + db 255 diff --git a/RefChip16/CPU.cpp b/RefChip16/CPU.cpp index 0efb70a..16e59bf 100644 --- a/RefChip16/CPU.cpp +++ b/RefChip16/CPU.cpp @@ -747,6 +747,7 @@ void CpuDiv() TempResult = (short)REG_X % (short)REG_Y; if((REG_X & 0x8000) ^ (REG_Y & 0x8000)) REG_X = TempResult + (short)REG_Y; else REG_X = TempResult; + CPU_LOG("Result is %d tempresult is %d", REG_X, TempResult); LogicCMP(REG_X); break; // Z = X MOD Y [z,n] diff --git a/RefChip16/D3DApp.cpp b/RefChip16/D3DApp.cpp index f9e4bff..c17bc33 100644 --- a/RefChip16/D3DApp.cpp +++ b/RefChip16/D3DApp.cpp @@ -235,16 +235,16 @@ void DrawSprite(unsigned short MemAddr, int X, int Y) void RedrawLastScreen() { //FPS_LOG("Starting redraw"); - int scale = 1; //Used for when the screen is bigger :P + unsigned short scale = 1; //Used for when the screen is bigger :P scale = SCREEN_WIDTH / 320; SDL_Rect rect = {0,0,SCREEN_WIDTH,SCREEN_HEIGHT}; SDL_FillRect(SDL_Display, &rect, pixelcolours[SpriteSet.BackgroundColour]); - + unsigned short u_Scale = (unsigned short)(scale - 1); //This used to be slow, but since changing to shaders, it seems quicker again, guess ive just gotta make sure i dont thrash it. - for(int i = 0; i < 240; i++){ + for(unsigned short i = 0; i < 240; i++){ - for(int j = 0; j < 320; j++){ + for(unsigned short j = 0; j < 320; j++){ if(ScreenBuffer[j][i] != 0) { @@ -256,14 +256,15 @@ void RedrawLastScreen() { if(ScreenBuffer[j-1][i] == ScreenBuffer[j][i] && ScreenBuffer[j][i-1] == ScreenBuffer[j][i]) { - SDL_Rect trect = {(j-1)*scale+(scale-1),(i-1)*scale+(scale-1),scale-1,scale-1}; + + SDL_Rect trect = {(j-1)*scale+ u_Scale,(i-1)*scale+u_Scale,u_Scale,u_Scale }; SDL_FillRect(SDL_Display, &trect, pixelcolours[ScreenBuffer[j][i]]); } if(ScreenBuffer[j-1][i] == ScreenBuffer[j][i] && ScreenBuffer[j][i+1] == ScreenBuffer[j][i]) { - SDL_Rect trect = {(j-1)*scale+(scale-1),(i+1)*scale,scale-1,scale-1}; + SDL_Rect trect = {(j-1)*scale+u_Scale,(i+1)*scale,u_Scale,u_Scale }; SDL_FillRect(SDL_Display, &trect, pixelcolours[ScreenBuffer[j][i]]); } @@ -271,14 +272,14 @@ void RedrawLastScreen() if(ScreenBuffer[j][i-1] == ScreenBuffer[j][i] && ScreenBuffer[j+1][i] == ScreenBuffer[j][i]) { - SDL_Rect trect = {(j+1)*scale,(i-1)*scale+(scale-1),scale-1,scale-1}; + SDL_Rect trect = {(j+1)*scale,(i-1)*scale+ u_Scale,u_Scale,u_Scale }; SDL_FillRect(SDL_Display, &trect, pixelcolours[ScreenBuffer[j][i]]); } if(ScreenBuffer[j+1][i] == ScreenBuffer[j][i] && ScreenBuffer[j][i+1] == ScreenBuffer[j][i]) { - SDL_Rect trect = {(j+1)*scale,(i+1)*scale,scale-1,scale-1}; + SDL_Rect trect = {(j+1)*scale,(i+1)*scale,u_Scale,u_Scale }; SDL_FillRect(SDL_Display, &trect, pixelcolours[ScreenBuffer[j][i]]); } } diff --git a/RefChip16/D3DApp.h b/RefChip16/D3DApp.h index a40c1c5..5bc933e 100644 --- a/RefChip16/D3DApp.h +++ b/RefChip16/D3DApp.h @@ -25,8 +25,8 @@ #include #include -extern int SCREEN_WIDTH; -extern int SCREEN_HEIGHT; +extern unsigned short SCREEN_WIDTH; +extern unsigned short SCREEN_HEIGHT; extern char MenuVSync; extern char Smoothing; diff --git a/RefChip16/Emitter.cpp b/RefChip16/Emitter.cpp index a0ff4fa..52d1e91 100644 --- a/RefChip16/Emitter.cpp +++ b/RefChip16/Emitter.cpp @@ -267,7 +267,14 @@ void Emitter::MUL16RtoEAX( X86RegisterType src ) ModRM(3, 4, src); } -/*DIVs - Make sure EDX is cleared!!*/ +/*DIVs - EDX is sign extension!!*/ +void Emitter::CDQ16() +{ + RefChip16RecCPU->AddBlockInstruction(); + *(unsigned char*)x86Ptr++ = 0x66; //Prefix not needed for native 32bit (0x66 for 16bit) + *(unsigned char*)x86Ptr++ = 0x99; +} + void Emitter::DIV16MtoEAX(unsigned int src ) { RefChip16RecCPU->AddBlockInstruction(); @@ -286,6 +293,14 @@ void Emitter::DIV16RtoEAX( X86RegisterType src ) ModRM(3, 6, src); } +void Emitter::IDIV16RtoEAX(X86RegisterType src) +{ + RefChip16RecCPU->AddBlockInstruction(); + *(unsigned char*)x86Ptr++ = 0x66; //Prefix not needed for native 32bit (0x66 for 16bit) + *(unsigned char*)x86Ptr++ = 0xF7; //The MOV to Mem from Reg opcode + ModRM(3, 7, src); +} + void Emitter::AND16ItoR( X86RegisterType dest, int imm) { RefChip16RecCPU->AddBlockInstruction(); diff --git a/RefChip16/Emitter.h b/RefChip16/Emitter.h index 8d1ab42..aa25b6e 100644 --- a/RefChip16/Emitter.h +++ b/RefChip16/Emitter.h @@ -61,8 +61,10 @@ class Emitter void SUB32ItoM(unsigned int dest, int imm); void MUL16MtoEAX(unsigned int src ); void MUL16RtoEAX( X86RegisterType src ); + void CDQ16(); void DIV16MtoEAX(unsigned int src ); void DIV16RtoEAX( X86RegisterType src ); + void IDIV16RtoEAX(X86RegisterType src); void AND16ItoM(unsigned int dest, int imm); void AND16ItoR( X86RegisterType dest, int imm); void AND32ItoR( X86RegisterType dest, int imm); diff --git a/RefChip16/RecCPU.cpp b/RefChip16/RecCPU.cpp index 64e4812..b34c116 100644 --- a/RefChip16/RecCPU.cpp +++ b/RefChip16/RecCPU.cpp @@ -33,6 +33,7 @@ void *codebuffer; //Memory pointer for allocated stuff we're storing our code #define CONST_PROP 1 #define REG_CACHING +#define REG_COUNT 8 #define REG_Z GPR[(recOpCode & 0xf)] #define REG_X GPR[((recOpCode >> 24) & 0xf)] @@ -41,9 +42,6 @@ void *codebuffer; //Memory pointer for allocated stuff we're storing our code #define Op_Y ((recOpCode >> 28) & 0xf) #define Op_Z (recOpCode & 0xf) #define IMMEDIATE ((unsigned short)(recOpCode & 0xFFFF)) -#define TestX 0 -#define TestZ 1 -#define TestTemp 2 unsigned short tempreg; @@ -55,13 +53,22 @@ struct CurrentInst unsigned int BlockInstructions; }; +struct LiveReg +{ + bool inuse; //Is the register live with some contents + unsigned short gprreg; //GPR register number that is in the X86 register + unsigned int age; //How many instructions it's been since this reg was last used + bool isdirty; //We use "Dirty" to describe if the contents are going to be different from the real register. Clean means it is a read + bool islocked; //Used for regs we never want to write to (like ESI which is used as a stack pointer) +}; + struct CurrentBlock { bool GPRIsConst[16]; unsigned short GPRConstVal[16]; //Currently only supports what is left in - //EAX due to lack of x86 registers! I guess SSE would be better for this. - unsigned short LiveGPRReg; + //Using 4 registers for now, will try more later if i can avoid the stack pointer. + LiveReg LiveGPRReg[REG_COUNT]; }; struct CurrentBlock GPRStatus; @@ -105,7 +112,15 @@ void RecCPU::ResetRecMem() recPC = 0; memset(codebuffer, NULL, sizeof(codebuffer)); FlushConstRegisters(false); - GPRStatus.LiveGPRReg = 0xffff; + FlushLiveRegisters(false); + for (int i = 0; i < REG_COUNT; i++) + { + GPRStatus.LiveGPRReg[i].age = 0; + GPRStatus.LiveGPRReg[i].inuse = false; + GPRStatus.LiveGPRReg[i].isdirty = false; + GPRStatus.LiveGPRReg[i].gprreg = 0xffff; + } + GPRStatus.LiveGPRReg[4].islocked = true; //Don't touch the Stack Pointer, this would be bad :P memset(RecMemory, NULL, sizeof(RecMemory)); memset(PCIndex, NULL, sizeof(PCIndex)); } @@ -153,6 +168,11 @@ void __fastcall recWriteMem(unsigned short location, unsigned short value) Memory[(location+1) & 0xffff] = value>>8; } +void __fastcall recPrintValue(unsigned short value) +{ + CPU_LOG("Result is %x", value); +} + unsigned char* RecCPU::RecompileBlock() { @@ -189,12 +209,15 @@ unsigned char* RecCPU::RecompileBlock() CPU_LOG("Unknown Op\n"); break; } + IncRegisterAge(); if(cycles + PCIndex[recPC].BlockCycles >= (nextvsync + ((1000000/60) * fps))) break; } PCIndex[recPC].EndPC = PC; - ClearLiveRegister(0xffff, true); + //ClearLiveRegister(0xffff, true); + //FPS_LOG("Block Length %x\n", PCIndex[recPC].BlockCycles); if(cpubranch != 3) RefChip16Emitter->ADD32ItoM((unsigned int)&cycles, PCIndex[recPC].BlockCycles); + FlushLiveRegisters(true); FlushConstRegisters(true); RefChip16Emitter->RET(); @@ -202,6 +225,7 @@ unsigned char* RecCPU::RecompileBlock() return StartPTR; } +//Flush all constant registers if modified back to the associated GPR void RecCPU::FlushConstRegisters(bool flush) { @@ -215,94 +239,410 @@ void RecCPU::FlushConstRegisters(bool flush) GPRStatus.GPRIsConst[i] = false; } } +} + + +/********************/ +/*RegCache Handliers*/ +/********************/ +//Increase the age since a register was last used (for freeing it up for another register) +void RecCPU::IncRegisterAge() { + for (int i = 0; i < REG_COUNT; i++) + { + if (GPRStatus.LiveGPRReg[i].inuse == true) { + GPRStatus.LiveGPRReg[i].age++; + } + } } -void RecCPU::CheckLiveRegister(unsigned char GPRReg, bool writeback) +//Move one register to another, or swap two over which is quicker than flushing the existing one. +void RecCPU::MoveLiveRegister(X86RegisterType toreg, X86RegisterType fromreg, bool swap = false) { -#ifdef REG_CACHING - if(CONST_PROP && GPRStatus.GPRIsConst[GPRReg] == true) CPU_LOG("REGCACHE WARNING - Const reg trying to be used as live reg!\n"); - if(GPRStatus.LiveGPRReg == GPRReg) + if (fromreg == toreg) //Already in there, no need to move. + return; + + if (GPRStatus.LiveGPRReg[fromreg].inuse == false) { - if(writeback == true) + CPU_LOG("Swap of %d to %d faied! to reg is empty.", fromreg, toreg); + return; + } + + if (swap == false || GPRStatus.LiveGPRReg[toreg].inuse == false) + { + if (GPRStatus.LiveGPRReg[toreg].inuse == true) { - //CPU_LOG("REGCACHE Writing back Reg %d as it's about to be swapped!\n", GPRReg); - RefChip16Emitter->MOV16RtoM((unsigned int)&GPR[GPRStatus.LiveGPRReg], EAX); + if (GPRStatus.LiveGPRReg[toreg].isdirty == true) + { + RefChip16Emitter->MOV16RtoM((unsigned int)&GPR[GPRStatus.LiveGPRReg[toreg].gprreg], toreg); + } } - //CPU_LOG("REGCACHE using live reg %d\n", GPRStatus.LiveGPRReg); - return; + RefChip16Emitter->MOV16RtoR(toreg, fromreg); + memcpy(&GPRStatus.LiveGPRReg[toreg], &GPRStatus.LiveGPRReg[fromreg], sizeof(LiveReg)); + GPRStatus.LiveGPRReg[fromreg].age = 0; + GPRStatus.LiveGPRReg[fromreg].inuse = false; + GPRStatus.LiveGPRReg[fromreg].isdirty = false; + GPRStatus.LiveGPRReg[fromreg].gprreg = 0xffff; + } + else //If the other reg is live with something. + { + LiveReg tempreginfo; + //CPU_LOG("Moving from %d to %d with swap", fromreg, toreg); + memcpy(&tempreginfo, &GPRStatus.LiveGPRReg[toreg], sizeof(LiveReg)); + RefChip16Emitter->PUSH32R(toreg); + //RefChip16Emitter->PUSH32R(fromreg); + RefChip16Emitter->MOV16RtoR(toreg, fromreg); + //RefChip16Emitter->POP32R(toreg); + RefChip16Emitter->POP32R(fromreg); + memcpy(&GPRStatus.LiveGPRReg[toreg], &GPRStatus.LiveGPRReg[fromreg], sizeof(LiveReg)); + memcpy(&GPRStatus.LiveGPRReg[fromreg], &tempreginfo, sizeof(LiveReg)); } +} + +//Sets a lock on a certain x86 reg to signal that we don't want its contents to change +//and if a reg needs to be forcefully free'd we don't want it taking this one. +void RecCPU::ToggleLockRegister(int reg, bool locked) { + GPRStatus.LiveGPRReg[reg].islocked = locked; +} - //Live Reg is different from the needed Reg, so we flush what's there. - if(GPRStatus.LiveGPRReg != 0xffff) +//Search for a free x86 register or free the least recently used one +int RecCPU::GetFreeLiveRegister(unsigned short GPRReg, bool isDestOnly) { + int oldestReadReg = -1; + unsigned int Readage = 0; + int oldestWrittenReg = -1; + unsigned int Writtenage = 0; + + //First loop through to see if any are currently unused noting the least recently used ones which are in use, just in case there isnt any free. + for (int i = 0; i < REG_COUNT; i++) { - //CPU_LOG("REGCACHE Flushing live reg %d\n", GPRStatus.LiveGPRReg); - RefChip16Emitter->MOV16RtoM((unsigned int)&GPR[GPRStatus.LiveGPRReg], EAX); + if (GPRStatus.LiveGPRReg[i].islocked == false) + { + if (GPRStatus.LiveGPRReg[i].inuse == false) + { + //Horray we found a spare register! + //Only copy the data to it if it isn't the destination only, there's no point else :P + if ((GPRReg & 0xfff0) != 0xfff0) + { + if (CONST_PROP && GPRStatus.GPRIsConst[GPRReg] == true) + { + if (isDestOnly == false) + { + RefChip16Emitter->MOV16ItoR((X86RegisterType)i, GPRStatus.GPRConstVal[GPRReg]); + + } + GPRStatus.LiveGPRReg[i].isdirty = true; //Set to true as const data is dirty data + GPRStatus.GPRIsConst[GPRReg] = false; + } + else + { + if (isDestOnly == false) + { + RefChip16Emitter->MOV16MtoR((X86RegisterType)i, (unsigned int)&GPR[GPRReg]); + GPRStatus.LiveGPRReg[i].isdirty = false; //Set to false for now as it should be the same as the current data. + } + else GPRStatus.LiveGPRReg[i].isdirty = true; + } + } + //Remember to set the "Dirty" flag if you write to this register. + GPRStatus.LiveGPRReg[i].inuse = true; + GPRStatus.LiveGPRReg[i].gprreg = GPRReg; + GPRStatus.LiveGPRReg[i].age = 0; + + return i; + } + if (GPRStatus.LiveGPRReg[i].isdirty == false) + { + if (GPRStatus.LiveGPRReg[i].age > Readage) { + Readage = GPRStatus.LiveGPRReg[i].age; + oldestReadReg = i; + } + } + else + { + if (GPRStatus.LiveGPRReg[i].age > Writtenage) { + Writtenage = GPRStatus.LiveGPRReg[i].age; + oldestWrittenReg = i; + } + } + } } + //First loop found nothing, but we made note of the oldest regs that were read only and written only. + //Written to regs are more likely to be used sooner (assumption, it depends!) so lets try getting rid of the read ones first. + //Simply because we don't have to write these back, so it will be quicker to use these regs up. + if (Readage > 0) + { + //CPU_LOG("Flushing least recently read dirty = %d", GPRStatus.LiveGPRReg[oldestReadReg].isdirty); + if(GPRStatus.LiveGPRReg[oldestReadReg].isdirty) + RefChip16Emitter->MOV16RtoM((unsigned int)&GPR[GPRStatus.LiveGPRReg[oldestReadReg].gprreg], (X86RegisterType)oldestReadReg); - RefChip16Emitter->MOV16MtoR(EAX, (unsigned int)&GPR[GPRReg]); - GPRStatus.LiveGPRReg = GPRReg; -#else - RefChip16Emitter->MOV16MtoR(EAX, (unsigned int)&GPR[GPRReg]); -#endif - //CPU_LOG("REGCACHE Live reg now %d\n", GPRStatus.LiveGPRReg); + if (!(GPRReg & 0xfff0)) + { + if (CONST_PROP && GPRStatus.GPRIsConst[GPRReg] == true) + { + if (isDestOnly == false) + { + RefChip16Emitter->MOV16ItoR((X86RegisterType)oldestReadReg, GPRStatus.GPRConstVal[GPRReg]); + } + GPRStatus.LiveGPRReg[oldestReadReg].isdirty = true; + GPRStatus.GPRIsConst[GPRReg] = false; + } + else + { + if (isDestOnly == false) + { + RefChip16Emitter->MOV16MtoR((X86RegisterType)oldestReadReg, (unsigned int)&GPR[GPRReg]); + GPRStatus.LiveGPRReg[oldestReadReg].isdirty = false; //Set to false for now as it should be the same as the current data. + } + else GPRStatus.LiveGPRReg[oldestReadReg].isdirty = true; + } + } + + GPRStatus.LiveGPRReg[oldestReadReg].gprreg = GPRReg; + GPRStatus.LiveGPRReg[oldestReadReg].age = 0; + + return oldestReadReg; + } + else + { + //CPU_LOG("Flushing least recently read dirty = %d", GPRStatus.LiveGPRReg[oldestWrittenReg].isdirty); + //First write back our dirty data + + RefChip16Emitter->MOV16RtoM((unsigned int)&GPR[GPRStatus.LiveGPRReg[oldestWrittenReg].gprreg], (X86RegisterType)oldestWrittenReg); + + if (!(GPRReg & 0xfff0)) + { + if (CONST_PROP && GPRStatus.GPRIsConst[GPRReg] == true) + { + if (isDestOnly == false) + { + RefChip16Emitter->MOV16ItoR((X86RegisterType)oldestWrittenReg, GPRStatus.GPRConstVal[GPRReg]); + + } + GPRStatus.LiveGPRReg[oldestWrittenReg].isdirty = true; //Set to true as const data is dirty data + GPRStatus.GPRIsConst[GPRReg] = false; + } + else + { + if (isDestOnly == false) + { + RefChip16Emitter->MOV16MtoR((X86RegisterType)oldestWrittenReg, (unsigned int)&GPR[GPRReg]); + } + else GPRStatus.LiveGPRReg[oldestWrittenReg].isdirty = true; //Set to false for now as it should be the same as the current data. + } + } + GPRStatus.LiveGPRReg[oldestWrittenReg].gprreg = GPRReg; + GPRStatus.LiveGPRReg[oldestWrittenReg].age = 0; + return oldestWrittenReg; + } + CPU_LOG("Error finding register to allocate!"); + return -1; } -void RecCPU::FlushLiveRegister() +//Search for the GPRReg in our live registers, if it finds it, return it, if not, make a new entry +int RecCPU::GetLiveRegister(unsigned short GPRReg, bool isDestOnly = false) { + + for (int i = 0; i < REG_COUNT; i++) //First loop through seeing if the register is actually live already + { + if (GPRStatus.LiveGPRReg[i].inuse == true) + { + if (GPRStatus.GPRIsConst[GPRStatus.LiveGPRReg[i].gprreg] == true) { + CPU_LOG("WARNING GPR %x Cached & Const!", GPRStatus.LiveGPRReg[i].gprreg); + } + } + //Could probably just check the reg number here, but just in case we forgot to unset it somewhere + if (GPRStatus.LiveGPRReg[i].gprreg == GPRReg && GPRStatus.LiveGPRReg[i].inuse == true) + { + GPRStatus.LiveGPRReg[i].age = 0; + return i; + } + + } + //If we got here, the register is not live so we need to check for a free register. + return GetFreeLiveRegister(GPRReg, isDestOnly); + +} + +int RecCPU::GetLiveRegisterNoAssign(unsigned short GPRReg) { + + for (int i = 0; i < REG_COUNT; i++) //First loop through seeing if the register is actually live already + { + if (GPRStatus.LiveGPRReg[i].inuse == true) + { + if (GPRStatus.GPRIsConst[GPRStatus.LiveGPRReg[i].gprreg] == true) { + CPU_LOG("WARNING GPR %x Cached & Const!", GPRStatus.LiveGPRReg[i].gprreg); + } + } + //Could probably just check the reg number here, but just in case we forgot to unset it somewhere + if (GPRStatus.LiveGPRReg[i].gprreg == GPRReg && GPRStatus.LiveGPRReg[i].inuse == true) + { + GPRStatus.LiveGPRReg[i].age = 0; + return i; + } + } + //If we got here, the register is not live. + return -1; + +} + +//livereg is the x86 register you are taking over +//newGPR is the GPR register you want it to represent +//EG you move a value from Y to X, to save a copy you can do ReAssignLiveRegister(yReg, X_Op) +void RecCPU::ReAssignLiveRegister(int livereg, int newGPR) +{ + int newReg = GetLiveRegisterNoAssign(newGPR); + //Flush the old data first, if it's dirty + if (newReg == livereg) + return; + + if (GPRStatus.LiveGPRReg[livereg].isdirty == true && GPRStatus.LiveGPRReg[livereg].inuse == true) + { + CPU_LOG("Live reg %d is dirty", livereg); + RefChip16Emitter->MOV16RtoM((unsigned int)&GPR[GPRStatus.LiveGPRReg[livereg].gprreg], (X86RegisterType)livereg); + } + + if (newReg != -1) { //A register already exists for the new GPR we want to use, that data is now invalid. + CPU_LOG("Flushing existing register for %d", newGPR); + + GPRStatus.LiveGPRReg[newReg].inuse = false; + GPRStatus.LiveGPRReg[newReg].gprreg = 0xffff; + GPRStatus.LiveGPRReg[newReg].age = 0; + GPRStatus.LiveGPRReg[newReg].isdirty = false; + } + if (GPRStatus.GPRIsConst[newGPR] == true) { + CPU_LOG("WARNING Reassigned GPR %x Cached & Const!", newGPR); + } + + GPRStatus.LiveGPRReg[livereg].inuse = true; + GPRStatus.LiveGPRReg[livereg].gprreg = newGPR; + GPRStatus.LiveGPRReg[livereg].age = 0; + GPRStatus.LiveGPRReg[livereg].isdirty = true; +} + +//Assigns a recently written to register the contents of a current register. (an instruction that writes to a reg directly. +//DOES NOT FLUSH +void RecCPU::AssignLiveRegister(unsigned char GPRReg, int x86Reg) +{ + if (GPRStatus.GPRIsConst[GPRReg] == true) { + CPU_LOG("WARNING Assigned GPR %x Cached & Const!", GPRReg); + } + FlushLiveRegister(GPRReg, false); //Double check it wasn't assigned elsewhere + GPRStatus.LiveGPRReg[x86Reg].inuse = true; + GPRStatus.LiveGPRReg[x86Reg].gprreg = GPRReg; + GPRStatus.LiveGPRReg[x86Reg].age = 0; + GPRStatus.LiveGPRReg[x86Reg].isdirty = true; //Set to false for now as it should be the same as the current data. +} +//Flush all used cached regs, writing back any "dirty" written data +void RecCPU::FlushLiveRegisters(bool flush) { + + //Flush any used registers that have been written and reset all the register information + for (int i = 0; i < REG_COUNT; i++) + { + if (flush && GPRStatus.LiveGPRReg[i].inuse == true && GPRStatus.LiveGPRReg[i].isdirty == true) { + RefChip16Emitter->MOV16RtoM((unsigned int)&GPR[GPRStatus.LiveGPRReg[i].gprreg], (X86RegisterType)i); + } + GPRStatus.LiveGPRReg[i].inuse = false; + GPRStatus.LiveGPRReg[i].gprreg = 0xffff; + GPRStatus.LiveGPRReg[i].isdirty = false; //Don't forget to copy its dirty status! Important! + GPRStatus.LiveGPRReg[i].age = 0; + } +} +//Flush a single x86 Register +void RecCPU::FlushLiveRegister(unsigned short GPRReg, bool flush) { + int x86reg = GetLiveRegisterNoAssign(GPRReg); + if (x86reg == -1) //Not found, so we don't care! + return; + //CPU_LOG("Flushing %x", x86reg); #ifdef REG_CACHING //CPU_LOG("REGCACHE reg %d is live, flushing back to reg, leaving in EAX!\n", GPRStatus.LiveGPRReg); - RefChip16Emitter->MOV16RtoM((unsigned int)&GPR[GPRStatus.LiveGPRReg], EAX); + if (GPRStatus.LiveGPRReg[x86reg].isdirty == true && flush == true) + { + RefChip16Emitter->MOV16RtoM((unsigned int)&GPR[GPRStatus.LiveGPRReg[x86reg].gprreg], (X86RegisterType)x86reg); + //RefChip16Emitter->XOR16RtoR((X86RegisterType)x86reg, (X86RegisterType)x86reg); + } + + GPRStatus.LiveGPRReg[x86reg].inuse = false; + GPRStatus.LiveGPRReg[x86reg].gprreg = 0xffff; + GPRStatus.LiveGPRReg[x86reg].isdirty = false; //Don't forget to copy its dirty status! Important! + GPRStatus.LiveGPRReg[x86reg].age = 0; #endif } -void RecCPU::ClearLiveRegister(unsigned short GPRReg, bool flush) -{ -#ifdef REG_CACHING - if(GPRStatus.LiveGPRReg != 0xffff && (GPRStatus.LiveGPRReg == GPRReg || GPRReg == 0xffff)) + +//Special handling for MUL/DIV instructions due to how x86 works +//Could be done in those instructions but it felt better to bring it all into one function +void RecCPU::SetupMulDivSrcRegister(unsigned short srcReg, unsigned short tarReg, bool isSigned) { + //DIV and MUL instructions are a pain in the ass and you can only write results to EAX with EDX being the remainder, + // so we need to salvage these if they have data in them. + // Additionally EDX is used as a sign extension of EAX for IDIV (which we use) + int curSrc = GetLiveRegister(srcReg); + + if (curSrc == -1) { - if(flush == true) + CPU_LOG("ERROR ALLOCATING Source in SetupMulDivSrcRegister Pos 1"); + } + else if (curSrc != 0) //Source not yet in EAX so swap it with whatever is + { + MoveLiveRegister(EAX, (X86RegisterType)curSrc, true); + curSrc = 0; + } + + ToggleLockRegister(curSrc, true); + + if (srcReg != tarReg) //They are different so we better check if the target is in ECX + { + int curTar = GetLiveRegister(tarReg); //See if Target is in the registers, if not move it in. + + if (curTar >= 0) { - //CPU_LOG("REGCACHE reg %d is live, flushing out!\n", GPRStatus.LiveGPRReg); - RefChip16Emitter->MOV16RtoM((unsigned int)&GPR[GPRStatus.LiveGPRReg], EAX); + if (curTar != ECX) { + bool doSwap = true; + if (curTar == EDX) //Div is going to use EDX, so we may as well get rid of the other live reg + { + doSwap = false; + } + MoveLiveRegister(ECX, (X86RegisterType)curTar, doSwap); //Swap them, in case the other reg is needed + } + } - //else //CPU_LOG("REGCACHE reg %d is live, asked not to flush!\n", GPRStatus.LiveGPRReg); - GPRStatus.LiveGPRReg = 0xffff; - } -#endif -} + else //tarReg is not currently in Memory, so we failed to get a reg, damn. + { + CPU_LOG("ERROR ALLOCATING tarReg in SetupMulDivSrcRegister Pos 1!"); + } + } -void RecCPU::MoveLiveRegister(unsigned short GPRReg, X86RegisterType to) -{ -#ifdef REG_CACHING - if(GPRStatus.LiveGPRReg == GPRReg) + ToggleLockRegister(curSrc, false); + + + if (GPRStatus.LiveGPRReg[EDX].inuse == true) { - //CPU_LOG("REGCACHE moving live reg %d to different x86 reg\n", GPRStatus.LiveGPRReg); - RefChip16Emitter->MOV16RtoR(to, EAX); + if (GPRStatus.LiveGPRReg[EDX].isdirty) + { + //If it's dirty, copy it back, if not, just pretend it wasn't there. + RefChip16Emitter->MOV16RtoM((unsigned int)&GPR[GPRStatus.LiveGPRReg[EDX].gprreg], EDX); + } + GPRStatus.LiveGPRReg[EDX].inuse = false; + GPRStatus.LiveGPRReg[EDX].gprreg = 0xffff; + GPRStatus.LiveGPRReg[EDX].age = 0; + GPRStatus.LiveGPRReg[EDX].isdirty = false; + + } + ToggleLockRegister(EDX, true); //Lock out EDX from being allocated. + if (isSigned) + { + RefChip16Emitter->CDQ16(); //EDX is the sign extension of EAX } else { - //CPU_LOG("REGCACHE non live reg being moved to different x86 Reg\n"); - RefChip16Emitter->MOV16MtoR(to, (unsigned int)&GPR[GPRReg]); + RefChip16Emitter->XOR16RtoR(EDX, EDX); } -#else - RefChip16Emitter->MOV16MtoR(to, (unsigned int)&GPR[GPRReg]); -#endif } -void RecCPU::SetLiveRegister(unsigned char GPRReg) -{ -#ifdef REG_CACHING - //if(GPRStatus.LiveGPRReg != 0xffff && GPRStatus.LiveGPRReg != GPRReg) - //CPU_LOG("REGCACHE Warning - Setting Live EAX Reg to %d, was %d data potentially lost, Make sure previous Op wrote back\n", GPRReg, GPRStatus.LiveGPRReg); - /*else - //CPU_LOG("REGCACHE Live EAX Reg set to %d\n", GPRReg);*/ - GPRStatus.LiveGPRReg = GPRReg; -#else - RefChip16Emitter->MOV16RtoM((unsigned int)&GPR[GPRReg], EAX); -#endif -} +/*****************************/ +/* Start of CPU Instructions */ +/*****************************/ + void RecCPU::recCpuCore() { //CPU_LOG("Core Recompiling %x from PC %x\n", recOpCode, PC-4); @@ -316,17 +656,14 @@ void RecCPU::recCpuCore() // CPU_LOG("Waiting for VBlank\n"); //The CPU waits for VSync so we fast forward here (Small Optimization) //If we emulate it as a loop properly, this will cause a lot of Rec overhead! - ClearLiveRegister(0xffff, true); + FlushLiveRegisters(true); RefChip16Emitter->CALL16((int)SkipToVBlank); RefChip16Emitter->MOV32ItoM((unsigned int)&PC, PC); cpubranch = 3; break; case 0x3: //Background Colour //CPU_LOG("Set BG colour to %x\n", OpCode & 0xf); - RefChip16Emitter->MOV16ItoM((unsigned int)&SpriteSet.BackgroundColour, recOpCode & 0xf); - ClearLiveRegister(0xffff, true); - break; case 0x4: // Set Sprite H/W RefChip16Emitter->MOV16ItoM((unsigned int)&SpriteSet.Height, (recOpCode >> 8) & 0xFF); @@ -335,11 +672,11 @@ void RecCPU::recCpuCore() break; case 0x7: //Random Number //CPU_LOG("Random number generated from %x", IMMEDIATE); - ClearLiveRegister(0xffff, true); + FlushLiveRegisters(true); RefChip16Emitter->MOV32ItoR(ECX, IMMEDIATE+1); RefChip16Emitter->CALL16((int)GenerateRandom); - - SetLiveRegister(Op_X); + AssignLiveRegister(Op_X, EAX); + //SetLiveRegister(Op_X); GPRStatus.GPRIsConst[Op_X] = false; break; @@ -350,7 +687,7 @@ void RecCPU::recCpuCore() RefChip16Emitter->MOV16ItoM((unsigned int)&SpriteSet.HorizontalFlip , (recOpCode >> 9) & 0x1); break; default: - ClearLiveRegister(0xffff, true); + FlushLiveRegisters(true); FlushConstRegisters(true); RefChip16Emitter->MOV32ItoM((unsigned int)&OpCode, recOpCode); RefChip16Emitter->MOV32ItoM((unsigned int)&PC, PC); @@ -359,10 +696,12 @@ void RecCPU::recCpuCore() } } + +//TODO - Bit more complicated than everything else void RecCPU::recCpuJump() { //CPU_LOG("Jump Recompiling %x from PC %x\n", recOpCode, PC-4); - ClearLiveRegister(0xffff, true); + FlushLiveRegisters(true); FlushConstRegisters(true); RefChip16Emitter->MOV32ItoM((unsigned int)&OpCode, recOpCode); //Need to write the PC as some Ops here will Store it @@ -373,71 +712,88 @@ void RecCPU::recCpuJump() void RecCPU::recCpuLoad() { //CPU_LOG("Load Recompiling %x from PC %x\n", recOpCode, PC-4); - + int regSrc = -1; switch((recOpCode >> 16) & 0xf) { //Copy Immediate to GPR X - case 0x0: - ClearLiveRegister(Op_X, false); //No need to flush it, its const or being written over + case 0x0: if(CONST_PROP) { + FlushLiveRegister(Op_X, false); //No need to flush it, its const or being written over + GPRStatus.GPRConstVal[Op_X] = IMMEDIATE; GPRStatus.GPRIsConst[Op_X] = true; + //FlushConstRegisters(true); } else { - RefChip16Emitter->MOV16ItoM((unsigned int)®_X, IMMEDIATE); + regSrc = GetLiveRegister(Op_X, true); + //CPU_LOG("RegSrc assigned to reg %d\n", regSrc); + if (regSrc >= 0) + { + RefChip16Emitter->MOV16ItoR((X86RegisterType)regSrc, IMMEDIATE); + GPRStatus.LiveGPRReg[regSrc].isdirty = true; + //FlushLiveRegister(Op_X, true); + } + else + { + FlushLiveRegister(Op_X, false); + RefChip16Emitter->MOV16ItoM((unsigned int)®_X, IMMEDIATE); + } } break; //Point Stack Pointer to Address case 0x1: RefChip16Emitter->MOV16ItoM((unsigned int)&StackPTR, IMMEDIATE); break; - //Load Register with value at imm address + //Load Register with value at imm address, shouldn't need to flush reg unless its in ECX case 0x2: - ClearLiveRegister(0xffff, (Op_X == GPRStatus.LiveGPRReg) ? false : true); + FlushLiveRegisters(true); RefChip16Emitter->MOV32ItoR(ECX, IMMEDIATE); RefChip16Emitter->CALL16((int)recReadMem); GPRStatus.GPRIsConst[Op_X] = false; - SetLiveRegister(Op_X); + AssignLiveRegister(Op_X, EAX); break; //Load X with value from memory using address in Y - case 0x3: + case 0x3: + FlushLiveRegisters(true); + if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) RefChip16Emitter->MOV16ItoR(ECX, GPRStatus.GPRConstVal[Op_Y]); else - MoveLiveRegister(Op_Y, ECX); - - ClearLiveRegister(0xffff, (Op_X == GPRStatus.LiveGPRReg) ? false : true); + RefChip16Emitter->MOV16MtoR(ECX, (unsigned int)®_Y); RefChip16Emitter->CALL16((int)recReadMem); GPRStatus.GPRIsConst[Op_X] = false; - SetLiveRegister(Op_X); + AssignLiveRegister(Op_X, EAX); break; //Load Y in to X case 0x4: if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) { - ClearLiveRegister(Op_X, false); + FlushLiveRegister(Op_X, false); GPRStatus.GPRConstVal[Op_X] = GPRStatus.GPRConstVal[Op_Y]; GPRStatus.GPRIsConst[Op_X] = true; } else { - CheckLiveRegister(Op_Y, true); - ClearLiveRegister(Op_Y, false); //Dont really need to do this here, but it supresses warnings on the swap (when logging). - SetLiveRegister(Op_X); + int yReg = GetLiveRegister(Op_Y); + if(Op_Y != Op_X) + FlushLiveRegister(Op_X, true); + + ReAssignLiveRegister(yReg, Op_X); GPRStatus.GPRIsConst[Op_X] = false; } break; default: - ClearLiveRegister(0xffff, true); + FlushLiveRegisters(true); FlushConstRegisters(true); RefChip16Emitter->MOV32ItoM((unsigned int)&OpCode, recOpCode); + RefChip16Emitter->MOV32ItoM((unsigned int)&PC, PC); RefChip16Emitter->CALL(CpuLoad); break; } @@ -451,50 +807,111 @@ void RecCPU::recCpuStore() { //Store X Register value in imm Address case 0x0: - + FlushLiveRegisters(true); if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true)RefChip16Emitter->MOV16ItoR(EDX, GPRStatus.GPRConstVal[Op_X]); - else MoveLiveRegister(Op_X, EDX); + else { + int xReg = GetLiveRegister(Op_X); + if (xReg >= 0) + { + MoveLiveRegister(EDX, (X86RegisterType)xReg); + FlushLiveRegister(Op_X, true); + } + else + RefChip16Emitter->MOV16MtoR(EDX, (unsigned int)®_X); + } + if(IMMEDIATE > 0) RefChip16Emitter->MOV32ItoR(ECX, IMMEDIATE); - ClearLiveRegister(0xffff, true); + else RefChip16Emitter->XOR16RtoR(ECX, ECX); + FlushLiveRegisters(false); RefChip16Emitter->CALL16((int)recWriteMem); break; - //Store X Regsiter value in address given by Y Register + //Store X Register value in address given by Y Register case 0x1: + FlushLiveRegisters(true); if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true)RefChip16Emitter->MOV16ItoR(EDX, GPRStatus.GPRConstVal[Op_X]); - else MoveLiveRegister(Op_X, EDX); + else { + int xReg = GetLiveRegister(Op_X); + if (xReg >= 0) + { + MoveLiveRegister(EDX, (X86RegisterType)xReg); + FlushLiveRegister(Op_X, true); //Just clear the rec info + } + else + RefChip16Emitter->MOV16MtoR(EDX, (unsigned int)®_X); + } if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true)RefChip16Emitter->MOV16ItoR(ECX, GPRStatus.GPRConstVal[Op_Y]); - else MoveLiveRegister(Op_Y, ECX); - ClearLiveRegister(0xffff, true); + else { + int yReg = GetLiveRegister(Op_Y); + if (yReg >= 0) + { + MoveLiveRegister(ECX, (X86RegisterType)yReg); + FlushLiveRegister(Op_Y, true); //Just clear the rec info + } + else + RefChip16Emitter->MOV16MtoR(ECX, (unsigned int)®_Y); + } + RefChip16Emitter->CALL16((int)recWriteMem); break; default: - ClearLiveRegister(0xffff, true); + FlushLiveRegisters(true); FlushConstRegisters(true); RefChip16Emitter->MOV32ItoM((unsigned int)&OpCode, recOpCode); + RefChip16Emitter->MOV32ItoM((unsigned int)&PC, PC); RefChip16Emitter->CALL(CpuStore); break; } } -void RecCPU::recADDCheckOVF() +//This function checks the Zero and Negative conditions from the results +void RecCPU::recTestLogic(X86RegisterType dReg) { - - RefChip16Emitter->XOR16RtoR(ECX, EDX); //Set if either is different - RefChip16Emitter->SHR16ItoR(ECX, 15); - RefChip16Emitter->CMP16ItoR(ECX, 0); - j32Ptr[0] = RefChip16Emitter->JG32(0); //X and Y were different so no overflow + RefChip16Emitter->CMP16ItoR(dReg, 0); //See if the result was zero + j32Ptr[0] = RefChip16Emitter->JNE32(0); //Jump if it's not zero + //Carry on if it is zero + RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); //Set the zero flag + + j32Ptr[1] = RefChip16Emitter->JMP32(0); //Done with Zero, skip to end! - RefChip16Emitter->XOR16RtoR(EDX, EAX); - RefChip16Emitter->SHR16ItoR(EDX, 15); - RefChip16Emitter->CMP16ItoR(EDX, 1); + RefChip16Emitter->x86SetJ32(j32Ptr[0]); //Return from skipping zero flag. + RefChip16Emitter->CMP16ItoR(dReg, 0); //Do same compare again to find out if it's greater or less than zero + j32Ptr[2] = RefChip16Emitter->JG32(0); //Jump if it's greater (don't set negative) + RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x80); //Set Negative Flag + + RefChip16Emitter->x86SetJ32(j32Ptr[1]); //Return from setting zero. + RefChip16Emitter->x86SetJ32(j32Ptr[2]); //Return from skipping negative flag. +} + +//EAX = Result ECX = Copy of Op_X //EDX = IMM or Op_Y +void RecCPU::recADDCheckOVF(X86RegisterType yReg, X86RegisterType dReg, X86RegisterType xTemp, bool XisY) +{ + if (XisY == false) + { + RefChip16Emitter->XOR16RtoR(xTemp, yReg); //Set if either is different + RefChip16Emitter->SHR16ItoR(xTemp, 15); + RefChip16Emitter->CMP16ItoR(xTemp, 0); + j32Ptr[0] = RefChip16Emitter->JG32(0); //X and Y were different so no overflow + + RefChip16Emitter->MOV16RtoR(xTemp, yReg); + RefChip16Emitter->XOR16RtoR(xTemp, dReg); + RefChip16Emitter->SHR16ItoR(xTemp, 15); + RefChip16Emitter->CMP16ItoR(xTemp, 1); + } + else //If X == Y then they are going to be the same, so the first jump would be true anyway. + { + RefChip16Emitter->MOV16RtoR(xTemp, yReg); + RefChip16Emitter->XOR16RtoR(xTemp, dReg); + RefChip16Emitter->SHR16ItoR(xTemp, 15); + RefChip16Emitter->CMP16ItoR(xTemp, 1); + } j32Ptr[1] = RefChip16Emitter->JNE32(0); //Result was the same for X and result so dont Overflow RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x40); //Set Overflow Flag - RefChip16Emitter->x86SetJ32( j32Ptr[0] ); //Return from skipping overflow flag. - RefChip16Emitter->x86SetJ32( j32Ptr[1] ); - + RefChip16Emitter->x86SetJ32(j32Ptr[0]); //Return from skipping overflow flag. + RefChip16Emitter->x86SetJ32(j32Ptr[1]); + } void RecCPU::recADDCheckCarry() @@ -506,6 +923,11 @@ void RecCPU::recADDCheckCarry() void RecCPU::recCpuAdd() { + int xReg = -1; + int yReg = -1; + int xTemp = -1; + int dReg = -1; + bool yIsTemp = false; //CPU_LOG("Add Recompiling %x from PC %x\n", recOpCode, PC-4); RefChip16Emitter->AND16ItoM((unsigned int)&Flag._u16, ~0xC6); @@ -517,10 +939,11 @@ void RecCPU::recCpuAdd() { int flagsettings = 0; int CalcResult = GPRStatus.GPRConstVal[Op_X] + IMMEDIATE; + CPU_LOG("X = X + imm, X = %d, imm = %d Result = %d\n", GPRStatus.GPRConstVal[Op_X], IMMEDIATE, CalcResult); //Carry, if not zero if(CalcResult > 0xFFFF) flagsettings |= 0x2; - - CalcResult &= 0xffff; + CPU_LOG("Flag = %d\n", flagsettings); + // CalcResult &= 0xffff; if(CalcResult == 0) flagsettings |= 0x4; //Negative Overflow @@ -538,22 +961,27 @@ void RecCPU::recCpuAdd() return; } else - { - - CheckLiveRegister(Op_X, false); //Sets it live, no need to change - - //If Immediate is 0, we dont need to add or alter REG + { + + xReg = GetLiveRegister(Op_X); + + dReg = xReg; + //If Immediate is 0, we dont need to add or alter REG, yReg represents IMM here if(IMMEDIATE != 0) - { - MoveLiveRegister(Op_X, ECX); - RefChip16Emitter->MOV16ItoR(EDX, IMMEDIATE); - - RefChip16Emitter->ADD16RtoR(EAX, EDX); - SetLiveRegister(Op_X); + { + xTemp = GetFreeLiveRegister(0xfffe, true); //Should come back with a number, one of 4 regs must be usable. + if (xTemp == -1) CPU_LOG("ALLOC ERROR ADD X = X + imm"); + RefChip16Emitter->MOV16RtoR((X86RegisterType)xTemp, (X86RegisterType)xReg); //Make a copy for later + + yReg = GetFreeLiveRegister(0xfffd, true); + yIsTemp = true; + RefChip16Emitter->MOV16ItoR((X86RegisterType)yReg, IMMEDIATE); + + RefChip16Emitter->ADD16RtoR((X86RegisterType)dReg, (X86RegisterType)yReg); } else { - RefChip16Emitter->CMP16ItoR(EAX, 0); //See if the result was zero + RefChip16Emitter->CMP16ItoR((X86RegisterType)xReg, 0); //See if the result was zero j32Ptr[0] = RefChip16Emitter->JNE32(0); //Jump if it's not zero //Carry on if it is zero @@ -595,33 +1023,46 @@ void RecCPU::recCpuAdd() } else { - - if(Op_X == Op_Y) + if (Op_X == Op_Y) //If we reached here, neither is const { - //If we reached here then it is definately not a const - CheckLiveRegister(Op_X, false); - MoveLiveRegister(Op_X, ECX); - RefChip16Emitter->ADD16RtoR(EAX, EAX); + xReg = GetLiveRegister(Op_X); //Sets it live, no need to change + dReg = xReg; + + xTemp = GetFreeLiveRegister(0xfffe, true); //Should come back with a number, one of 4 regs must be usable. + if (xTemp == -1) CPU_LOG("ALLOC ERROR ADD X = X + imm"); + + RefChip16Emitter->MOV16RtoR((X86RegisterType)xTemp, (X86RegisterType)xReg); //Make a copy for later + yReg = xTemp; //This is going to be used for the flag calculation, best get it right. + + RefChip16Emitter->ADD16RtoR((X86RegisterType)dReg, (X86RegisterType)yReg); } else { - if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true)RefChip16Emitter->MOV16ItoR(EDX, GPRStatus.GPRConstVal[Op_Y]); - else MoveLiveRegister(Op_Y, EDX); + if (CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) + { + yReg = GetFreeLiveRegister(0xfffd, true); + yIsTemp = true; + RefChip16Emitter->MOV16ItoR((X86RegisterType)yReg, GPRStatus.GPRConstVal[Op_Y]); + } + else yReg = GetLiveRegister(Op_Y); - if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) + if (CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) { - ClearLiveRegister(0xffff, true); - RefChip16Emitter->MOV16ItoR(EAX, GPRStatus.GPRConstVal[Op_X]); + xReg = GetLiveRegister(Op_X, true); + + RefChip16Emitter->MOV16ItoR((X86RegisterType)xReg, GPRStatus.GPRConstVal[Op_X]); } - else CheckLiveRegister(Op_X, false); - MoveLiveRegister(Op_X, ECX); + else xReg = GetLiveRegister(Op_X); + dReg = xReg; + xTemp = GetFreeLiveRegister(0xfffe, true); //Should come back with a number, one of 4 regs must be usable. + if (xTemp == -1) CPU_LOG("ALLOC ERROR ADD X = X + imm"); + RefChip16Emitter->MOV16RtoR((X86RegisterType)xTemp, (X86RegisterType)xReg); //Make a copy for later - RefChip16Emitter->ADD16RtoR(EAX, EDX); + RefChip16Emitter->ADD16RtoR((X86RegisterType)dReg, (X86RegisterType)yReg); + GPRStatus.GPRIsConst[Op_X] = false; } - GPRStatus.GPRIsConst[Op_X] = false; - //Just in case X was a const - SetLiveRegister(Op_X); + } break; //Z = X + Y [c,z,o,n] @@ -648,7 +1089,7 @@ void RecCPU::recCpuAdd() GPRStatus.GPRConstVal[Op_Z] = CalcResult; GPRStatus.GPRIsConst[Op_Z] = true; - ClearLiveRegister(Op_Z, false); + FlushLiveRegister(Op_Z, false); RefChip16Emitter->MOV16ItoM((unsigned int)&Flag._u16, flagsettings); return; } @@ -656,65 +1097,136 @@ void RecCPU::recCpuAdd() { if(Op_X == Op_Y) { - //If we reached here then it is definately not a const - CheckLiveRegister(Op_X, (Op_X == Op_Z) ? false : true); - MoveLiveRegister(Op_X, ECX); - RefChip16Emitter->ADD16RtoR(EAX, EAX); + //If we reached here then both are definately not a const + xReg = GetLiveRegister(Op_X); + yReg = xReg; + if (Op_X == Op_Z) + { + dReg = xReg; + } + else + { + dReg = GetLiveRegister(Op_Z, true); + RefChip16Emitter->MOV16RtoR((X86RegisterType)dReg, (X86RegisterType)xReg); + } + xTemp = GetFreeLiveRegister(0xfffe, true); //Should come back with a number, one of 4 regs must be usable. + if (xTemp == -1) CPU_LOG("ALLOC ERROR ADD X = X + imm"); + RefChip16Emitter->MOV16RtoR((X86RegisterType)xTemp, (X86RegisterType)xReg); //Make a copy for later + + RefChip16Emitter->ADD16RtoR((X86RegisterType)dReg, (X86RegisterType)yReg); } else { - if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true)RefChip16Emitter->MOV16ItoR(EDX, GPRStatus.GPRConstVal[Op_Y]); - else MoveLiveRegister(Op_Y, EDX); + xTemp = GetFreeLiveRegister(0xfffe, true); //Should come back with a number, one of 4 regs must be usable. + if (xTemp == -1) CPU_LOG("ALLOC ERROR ADD X = X + imm"); - if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) + if (CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) + { + xReg = GetLiveRegister(Op_X, true); + RefChip16Emitter->MOV16ItoR((X86RegisterType)xReg, GPRStatus.GPRConstVal[Op_X]); + GPRStatus.LiveGPRReg[xReg].isdirty = true; + if (Op_X != Op_Z) { + GPRStatus.GPRIsConst[Op_X] = false; + } + } + else xReg = GetLiveRegister(Op_X); + + if (CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) { - ClearLiveRegister(0xffff, true); - RefChip16Emitter->MOV16ItoR(EAX, GPRStatus.GPRConstVal[Op_X]); + + if (Op_Y != Op_Z) + { + yReg = GetLiveRegister(0xfffd, true); + yIsTemp = true; + } + else + { + yReg = GetLiveRegister(Op_Y); + GPRStatus.LiveGPRReg[yReg].isdirty = true; + GPRStatus.GPRIsConst[Op_Y] = false; + } + RefChip16Emitter->MOV16ItoR((X86RegisterType)yReg, GPRStatus.GPRConstVal[Op_Y]); } - else CheckLiveRegister(Op_X, (Op_X == Op_Z) ? false : true); + else yReg = GetLiveRegister(Op_Y); - MoveLiveRegister(Op_X, ECX); - RefChip16Emitter->ADD16RtoR(EAX, EDX); + if (Op_X == Op_Z) + { + dReg = xReg; + RefChip16Emitter->MOV16RtoR((X86RegisterType)xTemp, (X86RegisterType)xReg); //Make a copy for later + RefChip16Emitter->ADD16RtoR((X86RegisterType)dReg, (X86RegisterType)yReg); + } + else if(Op_Y == Op_Z) + { + dReg = yReg; + yReg = GetLiveRegister(0xfffd, true); + yIsTemp = true; + RefChip16Emitter->MOV16RtoR((X86RegisterType)yReg, (X86RegisterType)dReg); //Make a copy for later + RefChip16Emitter->MOV16RtoR((X86RegisterType)xTemp, (X86RegisterType)yReg); //Make a copy for later + RefChip16Emitter->ADD16RtoR((X86RegisterType)dReg, (X86RegisterType)xReg); + } + else + { + dReg = GetLiveRegisterNoAssign(Op_Z); + if (dReg >= 0) //There is a live reg for it) + { + FlushLiveRegister(Op_Z, false); + } + dReg = xReg; + ReAssignLiveRegister(dReg, Op_Z); //reassign to different GPR as we're overwriting x + RefChip16Emitter->ADD16RtoR((X86RegisterType)xReg, (X86RegisterType)yReg); + } } - SetLiveRegister(Op_Z); GPRStatus.GPRIsConst[Op_Z] = false; } break; default: - ClearLiveRegister(0xffff, true); + FlushLiveRegisters(true); FlushConstRegisters(true); RefChip16Emitter->MOV32ItoM((unsigned int)&OpCode, recOpCode); + RefChip16Emitter->MOV32ItoM((unsigned int)&PC, PC); RefChip16Emitter->CALL(CpuAdd); return; break; } - + RefChip16Emitter->CMP16RtoR((X86RegisterType)xReg, (X86RegisterType)yReg); recADDCheckCarry(); - recTestLogic(); - recADDCheckOVF(); + recTestLogic((X86RegisterType)dReg); + recADDCheckOVF((X86RegisterType)yReg, (X86RegisterType)dReg, (X86RegisterType)xTemp, (xReg == yReg)); + + //Clear out temporary registers + if (yIsTemp == true) + { + FlushLiveRegister(0xfffd, false); + } + FlushLiveRegister(0xfffe, false); + GPRStatus.LiveGPRReg[dReg].isdirty = true; + } -void RecCPU::recSUBCheckOVF() +void RecCPU::recSUBCheckOVF(X86RegisterType yReg, X86RegisterType dReg, X86RegisterType xTemp, bool XisY) { - if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true)RefChip16Emitter->MOV16ItoR(EDX, GPRStatus.GPRConstVal[Op_X]); - else RefChip16Emitter->MOV16MtoR(EDX, (unsigned int)®_X); - RefChip16Emitter->XOR16RtoR(ECX, EDX); - RefChip16Emitter->SHR16ItoR(ECX, 15); - RefChip16Emitter->CMP16ItoR(ECX, 1); - - j32Ptr[5] = RefChip16Emitter->JNE32(0); //Result was the same for X and Y so dont Overflow - RefChip16Emitter->XOR16RtoR(EDX, EAX); - RefChip16Emitter->SHR16ItoR(EDX, 15); - RefChip16Emitter->CMP16ItoR(EDX, 1); - j32Ptr[6] = RefChip16Emitter->JNE32(0); //Result was the same for X and Y so dont Overflow - - RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x40); //Set Overflow Flag - - RefChip16Emitter->x86SetJ32( j32Ptr[5] ); //Return from skipping overflow flag. - RefChip16Emitter->x86SetJ32( j32Ptr[6] ); - - + if (XisY == false) + { + if(GPRStatus.LiveGPRReg[yReg].gprreg != 0xfffd) + FlushLiveRegister(Op_Y, true); + + RefChip16Emitter->XOR16RtoR(yReg, xTemp); //Set if either is different + RefChip16Emitter->SHR16ItoR(yReg, 15); + RefChip16Emitter->CMP16ItoR(yReg, 1); + j32Ptr[0] = RefChip16Emitter->JNE32(0); //Result was the same for X and Y so dont Overflow + + //RefChip16Emitter->MOV16RtoR(xTemp, yReg); + RefChip16Emitter->XOR16RtoR(xTemp, dReg); + RefChip16Emitter->SHR16ItoR(xTemp, 15); + RefChip16Emitter->CMP16ItoR(xTemp, 1); + j32Ptr[1] = RefChip16Emitter->JNE32(0); //Result was the same for X and result so dont Overflow + RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x40); //Set Overflow Flag + + RefChip16Emitter->x86SetJ32(j32Ptr[0]); //Return from skipping overflow flag. + RefChip16Emitter->x86SetJ32(j32Ptr[1]); + } + //else //If X == Y then they are going to be the same, it will never overflow } void RecCPU::recSUBCheckCarry() @@ -727,6 +1239,11 @@ void RecCPU::recSUBCheckCarry() } void RecCPU::recCpuSub() { + int xReg = -1; + int yReg = -1; + int xTemp = -1; + int dReg = -1; + bool yIsTemp = false; //CPU_LOG("Sub Recompiling %x from PC %x\n", recOpCode, PC-4); RefChip16Emitter->AND16ItoM((unsigned int)&Flag._u16, ~0xC6); @@ -759,22 +1276,29 @@ void RecCPU::recCpuSub() return; } else - { - - CheckLiveRegister(Op_X, false); - RefChip16Emitter->MOV16ItoR(ECX, IMMEDIATE); - - - RefChip16Emitter->CMP16RtoR(EAX, ECX); - recSUBCheckCarry(); + { + GPRStatus.GPRIsConst[Op_X] = false; + xReg = GetLiveRegister(Op_X); + yReg = GetLiveRegister(0xfffd, true); + yIsTemp = true; + dReg = xReg; + + RefChip16Emitter->MOV16ItoR((X86RegisterType)yReg, IMMEDIATE); + + if(IMMEDIATE != 0) { - RefChip16Emitter->SUB16RtoR(EAX, ECX); - recSUBCheckOVF(); - } + xTemp = GetFreeLiveRegister(0xfffe, true); //Should come back with a number, one of 4 regs must be usable. + if (xTemp == -1) CPU_LOG("ALLOC ERROR ADD X = X + imm"); + RefChip16Emitter->MOV16RtoR((X86RegisterType)xTemp, (X86RegisterType)xReg); //Make a copy for later - SetLiveRegister(Op_X); - recTestLogic(); + RefChip16Emitter->SUB16RtoR((X86RegisterType)xReg, (X86RegisterType)yReg); + + recSUBCheckCarry(); + recSUBCheckOVF((X86RegisterType)yReg, (X86RegisterType)dReg, (X86RegisterType)xTemp, false); + } + + recTestLogic((X86RegisterType)dReg); } break; //X = X - Y [c,z,o,n] @@ -811,14 +1335,13 @@ void RecCPU::recCpuSub() { GPRStatus.GPRConstVal[Op_X] = 0; GPRStatus.GPRIsConst[Op_X] = true; - ClearLiveRegister(Op_X, false); + FlushLiveRegister(Op_X, false); } else { #ifdef REG_CACHING - ClearLiveRegister(0xffff, (Op_X == GPRStatus.LiveGPRReg) ? false : true); - RefChip16Emitter->XOR16RtoR(EAX, EAX); - SetLiveRegister(Op_X); + xReg = GetLiveRegister(Op_X, true); + RefChip16Emitter->XOR16RtoR((X86RegisterType)xReg, (X86RegisterType)xReg); #else RefChip16Emitter->MOV16ItoM((unsigned int)®_X, 0); #endif @@ -826,25 +1349,33 @@ void RecCPU::recCpuSub() } else { - if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true)RefChip16Emitter->MOV16ItoR(ECX, GPRStatus.GPRConstVal[Op_Y]); - else MoveLiveRegister(Op_Y, ECX); + if (CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) + { + yReg = GetLiveRegister(0xfffd, true); + yIsTemp = true; + RefChip16Emitter->MOV16ItoR((X86RegisterType)yReg, GPRStatus.GPRConstVal[Op_Y]); + } + else yReg = GetLiveRegister(Op_Y); if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) { - ClearLiveRegister(0xffff, true); - RefChip16Emitter->MOV16ItoR(EAX, GPRStatus.GPRConstVal[Op_X]); + xReg = GetLiveRegister(Op_X, true); + RefChip16Emitter->MOV16ItoR((X86RegisterType)xReg, GPRStatus.GPRConstVal[Op_X]); } - else CheckLiveRegister(Op_X, false); + else xReg = GetLiveRegister(Op_X); - RefChip16Emitter->CMP16RtoR(EAX, ECX); + dReg = xReg; + xTemp = GetFreeLiveRegister(0xfffe, true); //Should come back with a number, one of 4 regs must be usable. + if (xTemp == -1) CPU_LOG("ALLOC ERROR ADD X = X + imm"); + RefChip16Emitter->MOV16RtoR((X86RegisterType)xTemp, (X86RegisterType)xReg); //Make a copy for later + + RefChip16Emitter->SUB16RtoR((X86RegisterType)xReg, (X86RegisterType)yReg); recSUBCheckCarry(); - RefChip16Emitter->SUB16RtoR(EAX, ECX); - recSUBCheckOVF(); + recSUBCheckOVF((X86RegisterType)yReg, (X86RegisterType)dReg, (X86RegisterType)xTemp, false); - SetLiveRegister(Op_X); //In case X was const, we need to make it the live reg GPRStatus.GPRIsConst[Op_X] = false; - recTestLogic(); + recTestLogic((X86RegisterType)dReg); } } break; @@ -870,7 +1401,7 @@ void RecCPU::recCpuSub() GPRStatus.GPRConstVal[Op_Z] = CalcResult; GPRStatus.GPRIsConst[Op_Z] = true; - ClearLiveRegister(Op_Z, false); //Incase it's different from X and Y and was live + FlushLiveRegister(Op_Z, false); //Incase it's different from X and Y and was live RefChip16Emitter->MOV16ItoM((unsigned int)&Flag._u16, flagsettings); return; } @@ -882,16 +1413,15 @@ void RecCPU::recCpuSub() if(CONST_PROP) { - ClearLiveRegister(Op_Z, false); //Incase it's different from X and Y and was live + FlushLiveRegister(Op_Z, false); //Incase it's different from X and Y and was live GPRStatus.GPRConstVal[Op_Z] = 0; GPRStatus.GPRIsConst[Op_Z] = true; } else { #ifdef REG_CACHING - ClearLiveRegister(0xffff, (Op_Z == GPRStatus.LiveGPRReg) ? false : true); - RefChip16Emitter->XOR16RtoR(EAX, EAX); - SetLiveRegister(Op_Z); + dReg = GetLiveRegister(Op_Z, true); + RefChip16Emitter->XOR16RtoR((X86RegisterType)dReg, (X86RegisterType)dReg); #else RefChip16Emitter->MOV16ItoM((unsigned int)®_Z, 0); #endif @@ -900,24 +1430,78 @@ void RecCPU::recCpuSub() } else { - if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true)RefChip16Emitter->MOV16ItoR(ECX, GPRStatus.GPRConstVal[Op_Y]); - else MoveLiveRegister(Op_Y, ECX); + xTemp = GetFreeLiveRegister(0xfffe, true); //Should come back with a number, one of 4 regs must be usable. + if (xTemp == -1) CPU_LOG("ALLOC ERROR ADD X = X + imm"); - if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) + if (CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) { - ClearLiveRegister(0xffff, true); - RefChip16Emitter->MOV16ItoR(EAX, GPRStatus.GPRConstVal[Op_X]); + xReg = GetLiveRegister(Op_X, true); + RefChip16Emitter->MOV16ItoR((X86RegisterType)xReg, GPRStatus.GPRConstVal[Op_X]); + if (Op_X != Op_Z) { + GPRStatus.GPRIsConst[Op_X] = false; + GPRStatus.LiveGPRReg[xReg].isdirty = true; + } } - else CheckLiveRegister(Op_X, (Op_X == Op_Z) ? false : true); + else xReg = GetLiveRegister(Op_X); - RefChip16Emitter->CMP16RtoR(EAX, ECX); - recSUBCheckCarry(); - RefChip16Emitter->SUB16RtoR(EAX, ECX); - recSUBCheckOVF(); - RefChip16Emitter->MOV16RtoM((unsigned int)®_Z, EAX); - GPRStatus.GPRIsConst[Op_Z] = false; - SetLiveRegister(Op_Z); - recTestLogic(); + if (CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) + { + yReg = GetLiveRegister(0xfffd, true); + if (Op_Y != Op_Z) + { + yIsTemp = true; + } + RefChip16Emitter->MOV16ItoR((X86RegisterType)yReg, GPRStatus.GPRConstVal[Op_Y]); + } + else yReg = GetLiveRegister(Op_Y); + + + if (Op_X == Op_Z) + { + dReg = xReg; + RefChip16Emitter->MOV16RtoR((X86RegisterType)xTemp, (X86RegisterType)xReg); //Make a copy for later + + RefChip16Emitter->SUB16RtoR((X86RegisterType)dReg, (X86RegisterType)yReg); + recSUBCheckCarry(); + recSUBCheckOVF((X86RegisterType)yReg, (X86RegisterType)dReg, (X86RegisterType)xTemp, false); + GPRStatus.GPRIsConst[Op_Z] = false; + recTestLogic((X86RegisterType)dReg); + } + else if (Op_Y == Op_Z) //This is a pain as you have to subtract in the right order, will need all 4 regs + { + dReg = yReg; + yReg = GetFreeLiveRegister(0xfffd, true); + yIsTemp = true; + RefChip16Emitter->MOV16RtoR((X86RegisterType)xTemp, (X86RegisterType)xReg); //Make a copy for later + RefChip16Emitter->MOV16RtoR((X86RegisterType)yReg, (X86RegisterType)dReg); + RefChip16Emitter->MOV16RtoR((X86RegisterType)dReg, (X86RegisterType)xReg); + + RefChip16Emitter->SUB16RtoR((X86RegisterType)dReg, (X86RegisterType)yReg); + recSUBCheckCarry(); + recSUBCheckOVF((X86RegisterType)yReg, (X86RegisterType)dReg, (X86RegisterType)xTemp, false); + GPRStatus.GPRIsConst[Op_Z] = false; + recTestLogic((X86RegisterType)dReg); + + } + else + { + dReg = GetLiveRegister(Op_Z); + //if (dReg >= 0) //There is a live reg for it) + //{ + // FlushLiveRegister(Op_Z, false); + //} + //dReg = xReg; + RefChip16Emitter->MOV16RtoR((X86RegisterType)xTemp, (X86RegisterType)xReg); + RefChip16Emitter->MOV16RtoR((X86RegisterType)dReg, (X86RegisterType)xReg); + + //ReAssignLiveRegister(dReg, Op_Z); + RefChip16Emitter->SUB16RtoR((X86RegisterType)dReg, (X86RegisterType)yReg); + recSUBCheckCarry(); + recSUBCheckOVF((X86RegisterType)yReg, (X86RegisterType)dReg, (X86RegisterType)xTemp, false); + GPRStatus.GPRIsConst[Op_Z] = false; + recTestLogic((X86RegisterType)dReg); + + } } } break; @@ -946,20 +1530,27 @@ void RecCPU::recCpuSub() } else { - CheckLiveRegister(Op_X, true); + GPRStatus.GPRIsConst[Op_X] = false; + xReg = GetLiveRegister(Op_X); + yReg = GetLiveRegister(0xfffd, true); + yIsTemp = true; + dReg = xReg; - RefChip16Emitter->MOV16ItoR(ECX, IMMEDIATE); - RefChip16Emitter->CMP16RtoR(EAX, ECX); - recSUBCheckCarry(); - if(IMMEDIATE != 0) + RefChip16Emitter->MOV16ItoR((X86RegisterType)yReg, IMMEDIATE); + + + if (IMMEDIATE != 0) { - ClearLiveRegister(Op_X, false); - RefChip16Emitter->SUB16RtoR(EAX, ECX); - recSUBCheckOVF(); - + xTemp = GetFreeLiveRegister(0xfffe, true); //Should come back with a number, one of 4 regs must be usable. + if (xTemp == -1) CPU_LOG("ALLOC ERROR ADD X = X + imm"); + RefChip16Emitter->MOV16RtoR((X86RegisterType)xTemp, (X86RegisterType)xReg); //Make a copy for later + FlushLiveRegister(Op_X, true); + RefChip16Emitter->SUB16RtoR((X86RegisterType)xReg, (X86RegisterType)yReg); + recSUBCheckCarry(); + recSUBCheckOVF((X86RegisterType)yReg, (X86RegisterType)dReg, (X86RegisterType)xTemp, false); } - recTestLogic(); + recTestLogic((X86RegisterType)dReg); } break; @@ -993,168 +1584,167 @@ void RecCPU::recCpuSub() RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); } else - { - if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) + { + if (CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) { - ClearLiveRegister(0xffff, true); - RefChip16Emitter->MOV16ItoR(EAX, GPRStatus.GPRConstVal[Op_X]); + yReg = GetLiveRegister(0xfffd, true); + yIsTemp = true; + RefChip16Emitter->MOV16ItoR((X86RegisterType)yReg, GPRStatus.GPRConstVal[Op_Y]); } - else CheckLiveRegister(Op_X, true); - - if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) + else yReg = GetLiveRegister(Op_Y); + + if (CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) { - if(GPRStatus.GPRConstVal[Op_Y] == 0) - { - CPU_LOG("SUB flags Y == 0\n"); //Only works when Y is 0 :( - RefChip16Emitter->CMP16ItoR(EAX, GPRStatus.GPRConstVal[Op_Y]); - recSUBCheckCarry(); - recSUBCheckOVF(); - recTestLogic(); - return; - } - else RefChip16Emitter->MOV16ItoR(ECX, GPRStatus.GPRConstVal[Op_Y]); + xReg = GetLiveRegister(Op_X, true); + RefChip16Emitter->MOV16ItoR((X86RegisterType)xReg, GPRStatus.GPRConstVal[Op_X]); } - else MoveLiveRegister(Op_Y, ECX); + else xReg = GetLiveRegister(Op_X); - ClearLiveRegister(Op_X, false); + dReg = xReg; + xTemp = GetFreeLiveRegister(0xfffe, true); //Should come back with a number, one of 4 regs must be usable. + if (xTemp == -1) CPU_LOG("ALLOC ERROR ADD X = X + imm"); + RefChip16Emitter->MOV16RtoR((X86RegisterType)xTemp, (X86RegisterType)xReg); //Make a copy for later - RefChip16Emitter->CMP16RtoR(EAX, ECX); + + FlushLiveRegister(Op_X, (GPRStatus.GPRIsConst[Op_X] == true) ? false : true); + RefChip16Emitter->SUB16RtoR((X86RegisterType)xReg, (X86RegisterType)yReg); recSUBCheckCarry(); - RefChip16Emitter->SUB16RtoR(EAX, ECX); - recSUBCheckOVF(); - recTestLogic(); + + recSUBCheckOVF((X86RegisterType)yReg, (X86RegisterType)dReg, (X86RegisterType)xTemp, false); + + recTestLogic((X86RegisterType)dReg); + } } break; default: - ClearLiveRegister(0xffff, true); + FlushLiveRegisters(true); FlushConstRegisters(true); RefChip16Emitter->MOV32ItoM((unsigned int)&OpCode, recOpCode); + RefChip16Emitter->MOV32ItoM((unsigned int)&PC, PC); RefChip16Emitter->CALL(CpuSub); + return; break; } - -} - -//This function checks the Zero and Negative conditions from the results of the Logic tests (XOR, AND, OR, NOT, NEG) -void RecCPU::recTestLogic() -{ - RefChip16Emitter->CMP16ItoR(EAX, 0); //See if the result was zero - j32Ptr[0] = RefChip16Emitter->JNE32(0); //Jump if it's not zero - //Carry on if it is zero - RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); //Set the zero flag - - j32Ptr[1] = RefChip16Emitter->JMP32(0); //Done with Zero, skip to end! - RefChip16Emitter->x86SetJ32( j32Ptr[0] ); //Return from skipping zero flag. + if (yIsTemp == true) + { + FlushLiveRegister(0xfffd, false); + } + FlushLiveRegister(0xfffe, false); + GPRStatus.LiveGPRReg[dReg].isdirty = true; - RefChip16Emitter->CMP16ItoR(EAX, 0); //Do same compare again to find out if it's greater or less than zero - j32Ptr[2] = RefChip16Emitter->JG32(0); //Jump if it's greater (don't set negative) - RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x80); //Set Negative Flag - - RefChip16Emitter->x86SetJ32( j32Ptr[1] ); //Return from setting zero. - RefChip16Emitter->x86SetJ32( j32Ptr[2] ); //Return from skipping negative flag. } void RecCPU::recCpuAND() { + int xReg = -1; + int yReg = -1; + int xTemp = -1; + int dReg = -1; + bool yIsTemp = false; //CPU_LOG("AND Recompiling %x from PC %x\n", recOpCode, PC-4); RefChip16Emitter->AND16ItoM((unsigned int)&Flag._u16, ~0x84); - - switch((recOpCode >> 16 & 0xf)) + + switch ((recOpCode >> 16 & 0xf)) { //X = X & imm [z,n] - case 0x0: - if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) - { + case 0x0: + if (CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) + { - GPRStatus.GPRConstVal[Op_X] &= IMMEDIATE; - - if(GPRStatus.GPRConstVal[Op_X] == 0)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); - else if(GPRStatus.GPRConstVal[Op_X] & 0x8000)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x80); - } - else + GPRStatus.GPRConstVal[Op_X] &= IMMEDIATE; + + if (GPRStatus.GPRConstVal[Op_X] == 0)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); + else if (GPRStatus.GPRConstVal[Op_X] & 0x8000)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x80); + return; + } + else + { + if (IMMEDIATE == 0) { - if(IMMEDIATE == 0) + RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); + + if (CONST_PROP) { - RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); + GPRStatus.GPRIsConst[Op_X] = true; + GPRStatus.GPRConstVal[Op_X] = 0; - if(CONST_PROP) - { - GPRStatus.GPRIsConst[Op_X] = true; - GPRStatus.GPRConstVal[Op_X] = 0; - - ClearLiveRegister(Op_X, false); - } - else - { -#ifdef REG_CACHING - ClearLiveRegister(0xffff, (Op_X == GPRStatus.LiveGPRReg) ? false : true); - RefChip16Emitter->XOR16RtoR(EAX, EAX); - SetLiveRegister(Op_X); -#else - RefChip16Emitter->MOV16ItoM((unsigned int)®_X, 0); -#endif - } + FlushLiveRegister(Op_X, false); } else { - CheckLiveRegister(Op_X, false); - RefChip16Emitter->AND16ItoR(EAX, IMMEDIATE); - SetLiveRegister(Op_X); - recTestLogic(); +#ifdef REG_CACHING + xReg = GetLiveRegister(Op_X); + dReg = xReg; + RefChip16Emitter->XOR16RtoR((X86RegisterType)dReg, (X86RegisterType)dReg); + GPRStatus.LiveGPRReg[dReg].isdirty = true; +#else + RefChip16Emitter->MOV16ItoM((unsigned int)®_X, 0); +#endif } - + return; } - break; - //X = X & Y [z,n] - case 0x1: - if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true && GPRStatus.GPRIsConst[Op_Y] == true) + else { - GPRStatus.GPRConstVal[Op_X] &= GPRStatus.GPRConstVal[Op_Y]; + dReg = GetLiveRegister(Op_X); + RefChip16Emitter->AND16ItoR((X86RegisterType)dReg, IMMEDIATE); + } - if(GPRStatus.GPRConstVal[Op_X] == 0)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); - else if(GPRStatus.GPRConstVal[Op_X] & 0x8000)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x80); + } + break; + //X = X & Y [z,n] + case 0x1: + if (CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true && GPRStatus.GPRIsConst[Op_Y] == true) + { + GPRStatus.GPRConstVal[Op_X] &= GPRStatus.GPRConstVal[Op_Y]; + + if (GPRStatus.GPRConstVal[Op_X] == 0)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); + else if (GPRStatus.GPRConstVal[Op_X] & 0x8000)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x80); + return; + } + else + { + if (Op_X == Op_Y) + { + dReg = GetLiveRegister(Op_X); + //Nothing to do, just check if the register is zero or negative } else { - if(Op_X == Op_Y) + if (CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) { - CheckLiveRegister(Op_X, false); + //If we hit here, X wasnt const + dReg = GetLiveRegister(Op_X); + RefChip16Emitter->AND16ItoR((X86RegisterType)dReg, GPRStatus.GPRConstVal[Op_Y]); } - else + else //X might be const instead { - if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) + if (CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) { - //If we hit here, X wasnt const - CheckLiveRegister(Op_X, false); - RefChip16Emitter->AND16ItoR(EAX, GPRStatus.GPRConstVal[Op_Y]); + yReg = GetLiveRegister(Op_Y); + dReg = GetLiveRegister(Op_X); //This will copy the const reg in for us + RefChip16Emitter->MOV16ItoR((X86RegisterType)dReg, GPRStatus.GPRConstVal[Op_X]); + RefChip16Emitter->AND16RtoR((X86RegisterType)dReg, (X86RegisterType)yReg); + GPRStatus.GPRIsConst[Op_X] = false; //should do this too } - else //X might be const instead + else { - if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) - { - CheckLiveRegister(Op_Y, true); // Write Y back if it was already live as we're about to lose it. - RefChip16Emitter->AND16ItoR(EAX, GPRStatus.GPRConstVal[Op_X]); - GPRStatus.GPRIsConst[Op_X] = false; - } - else - { - MoveLiveRegister(Op_Y, EDX); - CheckLiveRegister(Op_X, false); - RefChip16Emitter->AND16RtoR(EAX, EDX); - } - } - - SetLiveRegister(Op_X); + yReg = GetLiveRegister(Op_Y); + dReg = GetLiveRegister(Op_X); //This will copy the const reg in for us + RefChip16Emitter->AND16RtoR((X86RegisterType)dReg, (X86RegisterType)yReg); + GPRStatus.LiveGPRReg[dReg].isdirty = true; + } } - - recTestLogic(); - } + + recTestLogic((X86RegisterType)dReg); + return; + + } break; //Z = X & Y [z,n] case 0x2: @@ -1163,46 +1753,53 @@ void RecCPU::recCpuAND() GPRStatus.GPRConstVal[Op_Z] = GPRStatus.GPRConstVal[Op_X] & GPRStatus.GPRConstVal[Op_Y]; - if(GPRStatus.GPRConstVal[Op_Z] == 0)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); + if(GPRStatus.GPRConstVal[Op_Z] == 0)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); else if(GPRStatus.GPRConstVal[Op_Z] & 0x8000)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x80); GPRStatus.GPRIsConst[Op_Z] = true; - ClearLiveRegister(Op_Z, false); //Incase it's different from X and Y and was live + FlushLiveRegister(Op_Z, false); //Incase it's different from X and Y and was live + return; } else { - if(Op_X == Op_Y) + if(Op_X == Op_Y) { //If we reached here Op_X isnt const - CheckLiveRegister(Op_X, (Op_X == Op_Z) ? false : true); + dReg = GetLiveRegister(Op_X); + if (Op_Z != Op_X) + ReAssignLiveRegister(dReg, Op_Z); } else { if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) { //If we hit here, X wasnt const - CheckLiveRegister(Op_X, (Op_X == Op_Z) ? false : true); - RefChip16Emitter->AND16ItoR(EAX, GPRStatus.GPRConstVal[Op_Y]); + dReg = GetLiveRegister(Op_X); + ReAssignLiveRegister(dReg, Op_Z); + + RefChip16Emitter->AND16ItoR((X86RegisterType)dReg, GPRStatus.GPRConstVal[Op_Y]); + } else //X might be const instead { if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) { - CheckLiveRegister(Op_Y, (Op_Y == Op_Z) ? false : true); // Write Y back if it was already live as we're about to lose it (unless Y == Z). - RefChip16Emitter->AND16ItoR(EAX, GPRStatus.GPRConstVal[Op_X]); - + dReg = GetLiveRegister(Op_Y); + + ReAssignLiveRegister(dReg, Op_Z); + RefChip16Emitter->AND16ItoR((X86RegisterType)dReg, GPRStatus.GPRConstVal[Op_X]); + } - else + else { - MoveLiveRegister(Op_Y, EDX); - CheckLiveRegister(Op_X, (Op_X == Op_Z) ? false : true); - RefChip16Emitter->AND16RtoR(EAX, EDX); - } - } + dReg = GetLiveRegister(Op_X); + yReg = GetLiveRegister(Op_Y); + ReAssignLiveRegister(dReg, Op_Z); + RefChip16Emitter->AND16RtoR((X86RegisterType)dReg, (X86RegisterType)yReg); + } + } GPRStatus.GPRIsConst[Op_Z] = false; - SetLiveRegister(Op_Z); } - recTestLogic(); } break; //X & imm discard flags only [z,n] @@ -1210,23 +1807,25 @@ void RecCPU::recCpuAND() if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) { tempreg = GPRStatus.GPRConstVal[Op_X] & IMMEDIATE; - - if(tempreg == 0)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); + + if(tempreg == 0)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); else if(tempreg & 0x8000)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x80); + return; } else { if(IMMEDIATE == 0) { - RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); + RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); + return; } else { - CheckLiveRegister(Op_X, true); //The live instruction is different so copy it in, then we can ignore it. - - RefChip16Emitter->AND16ItoR(EAX, IMMEDIATE); - ClearLiveRegister(0xffff, false); - recTestLogic(); + dReg = GetLiveRegister(Op_X); //The live instruction is different so copy it in, then we can ignore it. + xTemp = GetLiveRegister(0xfffe, true); + RefChip16Emitter->MOV16RtoR((X86RegisterType)xTemp, (X86RegisterType)dReg); + RefChip16Emitter->AND16ItoR((X86RegisterType)xTemp, IMMEDIATE); + dReg = xTemp; } } break; @@ -1235,60 +1834,84 @@ void RecCPU::recCpuAND() if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true && GPRStatus.GPRIsConst[Op_Y] == true) { tempreg = GPRStatus.GPRConstVal[Op_X] & GPRStatus.GPRConstVal[Op_Y]; - - if(tempreg == 0)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); + + if(tempreg == 0)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); else if(tempreg & 0x8000)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x80); + return; } else { - if(Op_X == Op_Y) - { + if(Op_X == Op_Y) + { //If we reached here Op_X isnt const - CheckLiveRegister(Op_X, false); + //We can call this reg as it won't be modified anyway + dReg = GetLiveRegister(Op_X); } else { - CPU_LOG("AND3 X %d, Y %d X = %x Y = %x\n", GPRStatus.GPRIsConst[Op_X], GPRStatus.GPRIsConst[Op_Y], GPRStatus.GPRConstVal[Op_X], GPRStatus.GPRConstVal[Op_Y]); if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) { //If we hit here, X wasnt const - CheckLiveRegister(Op_X, true); - RefChip16Emitter->AND16ItoR(EAX, GPRStatus.GPRConstVal[Op_Y]); + xReg = GetLiveRegister(Op_X); + xTemp = GetLiveRegister(0xfffe, true); + dReg = xTemp; + RefChip16Emitter->MOV16RtoR((X86RegisterType)dReg, (X86RegisterType)xReg); + RefChip16Emitter->AND16ItoR((X86RegisterType)dReg, GPRStatus.GPRConstVal[Op_Y]); } else //X might be const instead { if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) { - CheckLiveRegister(Op_Y, true); // Write Y back if it was already live as we're about to lose it. - RefChip16Emitter->AND16ItoR(EAX, GPRStatus.GPRConstVal[Op_X]); - GPRStatus.GPRIsConst[Op_X] = false; + yReg = GetLiveRegister(Op_Y); + xTemp = GetLiveRegister(0xfffe, true); + dReg = xTemp; + RefChip16Emitter->MOV16RtoR((X86RegisterType)dReg, (X86RegisterType)yReg); + RefChip16Emitter->AND16ItoR((X86RegisterType)dReg, GPRStatus.GPRConstVal[Op_X]); } - else + else { - MoveLiveRegister(Op_Y, EDX); - CheckLiveRegister(Op_X, true); - RefChip16Emitter->AND16RtoR(EAX, EDX); - } - } + xReg = GetLiveRegister(Op_X); + yReg = GetLiveRegister(Op_Y); + xTemp = GetLiveRegister(0xfffe, true); + dReg = xTemp; + RefChip16Emitter->MOV16RtoR((X86RegisterType)dReg, (X86RegisterType)xReg); + RefChip16Emitter->AND16RtoR((X86RegisterType)dReg, (X86RegisterType)yReg); + } + } } - ClearLiveRegister(0xffff, false); - recTestLogic(); } break; - default: - ClearLiveRegister(0xffff, true); - FlushConstRegisters(true); - RefChip16Emitter->MOV32ItoM((unsigned int)&OpCode, recOpCode); - RefChip16Emitter->CALL(CpuAND); - break; + default: + FlushLiveRegisters(true); + FlushConstRegisters(true); + RefChip16Emitter->MOV32ItoM((unsigned int)&OpCode, recOpCode); + RefChip16Emitter->MOV32ItoM((unsigned int)&PC, PC); + RefChip16Emitter->CALL(CpuAND); + return; + break; } + recTestLogic((X86RegisterType)dReg); + if (yIsTemp == true) + { + FlushLiveRegister(0xfffd, false); + } + if (xTemp >= 0) + FlushLiveRegister(0xfffe, false); + + GPRStatus.LiveGPRReg[dReg].isdirty = true; + } void RecCPU::recCpuOR() { //CPU_LOG("OR Recompiling %x from PC %x\n", recOpCode, PC-4); - + int xReg = -1; + int yReg = -1; + int xTemp = -1; + int dReg = -1; + bool yIsTemp = false; + RefChip16Emitter->AND16ItoM((unsigned int)&Flag._u16, ~0x84); //ClearLiveRegister(0xffff, true); switch((recOpCode >> 16 & 0xf)) @@ -1303,22 +1926,19 @@ void RecCPU::recCpuOR() if(GPRStatus.GPRConstVal[Op_X] == 0)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); else if(GPRStatus.GPRConstVal[Op_X] & 0x8000)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x80); + return; } else { if(IMMEDIATE == 0) { - CheckLiveRegister(Op_X, false); + dReg = GetLiveRegister(Op_X); //Nothing to change, just load it in for checking } else { - CheckLiveRegister(Op_X, false); - RefChip16Emitter->OR16ItoR(EAX, IMMEDIATE); - SetLiveRegister(Op_X); - } - - recTestLogic(); - + dReg = GetLiveRegister(Op_X); + RefChip16Emitter->OR16ItoR((X86RegisterType)dReg, IMMEDIATE); + } } break; //X = X | Y [z,n] @@ -1331,45 +1951,40 @@ void RecCPU::recCpuOR() if(GPRStatus.GPRConstVal[Op_X] == 0)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); else if(GPRStatus.GPRConstVal[Op_X] & 0x8000)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x80); - + return; } else { if(Op_X == Op_Y) { //If we reached here Op_X isnt const - //FPS_LOG("OR X=Y is 0 %x\n", recOpCode); - CheckLiveRegister(Op_X, false); + dReg = GetLiveRegister(Op_X); //Nothing to change, just load it in for checking } else { if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) { //If we hit here, X wasnt const - CheckLiveRegister(Op_X, false); - RefChip16Emitter->OR16ItoR(EAX, GPRStatus.GPRConstVal[Op_Y]); + dReg = GetLiveRegister(Op_X); + RefChip16Emitter->OR16ItoR((X86RegisterType)dReg, GPRStatus.GPRConstVal[Op_Y]); } else //X might be const instead { if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) { - CheckLiveRegister(Op_Y, true); // Write Y back if it was already live as we're about to lose it. - RefChip16Emitter->OR16ItoR(EAX, GPRStatus.GPRConstVal[Op_X]); + dReg = GetLiveRegister(Op_Y); // Write Y back if it was already live as we're about to lose it. + ReAssignLiveRegister(dReg, Op_X); + RefChip16Emitter->OR16ItoR((X86RegisterType)dReg, GPRStatus.GPRConstVal[Op_X]); GPRStatus.GPRIsConst[Op_X] = false; } else { - MoveLiveRegister(Op_Y, EDX); - CheckLiveRegister(Op_X, false); - RefChip16Emitter->OR16RtoR(EAX, EDX); + yReg = GetLiveRegister(Op_Y); // Write Y back if it was already live as we're about to lose it. + dReg = GetLiveRegister(Op_X); + RefChip16Emitter->OR16RtoR((X86RegisterType)dReg, (X86RegisterType)yReg); } } - - SetLiveRegister(Op_X); - } - - recTestLogic(); - + } } break; //Z = X | Y [z,n] @@ -1383,55 +1998,75 @@ void RecCPU::recCpuOR() else if(GPRStatus.GPRConstVal[Op_Z] & 0x8000)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x80); GPRStatus.GPRIsConst[Op_Z] = true; - ClearLiveRegister(Op_Z, false); //Incase it's different from X and Y and was live + FlushLiveRegister(Op_Z, false); //Incase it's different from X and Y and was live + return; } else { if(Op_X == Op_Y) { //If we reached here neither are const - CheckLiveRegister(Op_X, (Op_X == Op_Z) ? false : true); + dReg = GetLiveRegister(Op_X); + ReAssignLiveRegister(dReg, Op_Z); } else { if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) { //If we hit here, X wasnt const - CheckLiveRegister(Op_X, (Op_X == Op_Z) ? false : true); - RefChip16Emitter->OR16ItoR(EAX, GPRStatus.GPRConstVal[Op_Y]); + dReg = GetLiveRegister(Op_X); + ReAssignLiveRegister(dReg, Op_Z); + RefChip16Emitter->OR16ItoR((X86RegisterType)dReg, GPRStatus.GPRConstVal[Op_Y]); } else //X might be const instead { + if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) { - CheckLiveRegister(Op_Y, (Op_Y == Op_Z) ? false : true); // Write Y back if it was already live as we're about to lose it (unless Y == Z). - RefChip16Emitter->OR16ItoR(EAX, GPRStatus.GPRConstVal[Op_X]); + dReg = GetLiveRegister(Op_Y); + ReAssignLiveRegister(dReg, Op_Z); + RefChip16Emitter->OR16ItoR((X86RegisterType)dReg, GPRStatus.GPRConstVal[Op_X]); } else { - MoveLiveRegister(Op_Y, EDX); - CheckLiveRegister(Op_X, (Op_X == Op_Z) ? false : true); - RefChip16Emitter->OR16RtoR(EAX, EDX); + dReg = GetLiveRegister(Op_X); + yReg = GetLiveRegister(Op_Y); + ReAssignLiveRegister(dReg, Op_Z); + RefChip16Emitter->OR16RtoR((X86RegisterType)dReg, (X86RegisterType)yReg); } - } - GPRStatus.GPRIsConst[Op_Z] = false; - SetLiveRegister(Op_Z); + } } - recTestLogic(); + GPRStatus.GPRIsConst[Op_Z] = false; } break; default: - ClearLiveRegister(0xffff, true); + FlushLiveRegisters(true); FlushConstRegisters(true); RefChip16Emitter->MOV32ItoM((unsigned int)&OpCode, recOpCode); + RefChip16Emitter->MOV32ItoM((unsigned int)&PC, PC); RefChip16Emitter->CALL(CpuOR); + return; break; } + recTestLogic((X86RegisterType)dReg); + if (yIsTemp == true) + { + FlushLiveRegister(0xfffd, false); + } + if (xTemp >= 0) + FlushLiveRegister(0xfffe, false); + + GPRStatus.LiveGPRReg[dReg].isdirty = true; } void RecCPU::recCpuXOR() { + int xReg = -1; + int yReg = -1; + int xTemp = -1; + int dReg = -1; + bool yIsTemp = false; //CPU_LOG("XOR Recompiling %x from PC %x\n", recOpCode, PC-4); RefChip16Emitter->AND16ItoM((unsigned int)&Flag._u16, ~0x84); //ClearLiveRegister(0xffff, true); @@ -1447,21 +2082,19 @@ void RecCPU::recCpuXOR() if(GPRStatus.GPRConstVal[Op_X] == 0)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); else if(GPRStatus.GPRConstVal[Op_X] & 0x8000)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x80); + return; } else { - if(IMMEDIATE == 0) + if (IMMEDIATE == 0) { - CheckLiveRegister(Op_X, false); + dReg = GetLiveRegister(Op_X); //Nothing to change, just load it in for checking } else { - CheckLiveRegister(Op_X, false); - RefChip16Emitter->XOR16ItoR(EAX, IMMEDIATE); - SetLiveRegister(Op_X); + dReg = GetLiveRegister(Op_X); + RefChip16Emitter->XOR16ItoR((X86RegisterType)dReg, IMMEDIATE); } - - recTestLogic(); } break; //X = X ^ Y [z,n] @@ -1472,56 +2105,43 @@ void RecCPU::recCpuXOR() if(GPRStatus.GPRConstVal[Op_X] == 0)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); else if(GPRStatus.GPRConstVal[Op_X] & 0x8000)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x80); - + return; } else { - if(Op_X == Op_Y) + if (Op_X == Op_Y) { - //FPS_LOG("XOR1 X=Y is 0 setting REG_%d to const %x\n", Op_X, recOpCode); - RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); - - if(CONST_PROP) - { - GPRStatus.GPRIsConst[Op_X] = true; - GPRStatus.GPRConstVal[Op_X] = 0; - ClearLiveRegister(Op_X, false); - } - else - { -#ifdef REG_CACHING - ClearLiveRegister(0xffff, (Op_X == GPRStatus.LiveGPRReg) ? false : true); - RefChip16Emitter->XOR16RtoR(EAX, EAX); - SetLiveRegister(Op_X); -#else - RefChip16Emitter->MOV16ItoM((unsigned int)®_X, 0); -#endif - } + //If we reached here Op_X isnt const + FlushLiveRegister(Op_X, false); //XORing itself will zero the register, so we can make it a const. + GPRStatus.GPRIsConst[Op_X] = true; + GPRStatus.GPRConstVal[Op_X] = 0; + RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); + return; } else { - if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) + if (CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) { - CheckLiveRegister(Op_X, false); - if(GPRStatus.GPRConstVal[Op_Y] != 0) //Only do this if Y isnt 0, else X doesnt change. - RefChip16Emitter->XOR16ItoR(EAX, GPRStatus.GPRConstVal[Op_Y]); + //If we hit here, X wasnt const + dReg = GetLiveRegister(Op_X); + RefChip16Emitter->XOR16ItoR((X86RegisterType)dReg, GPRStatus.GPRConstVal[Op_Y]); } - else if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) - { - CheckLiveRegister(Op_Y, true); - if(GPRStatus.GPRConstVal[Op_X] != 0) //Only do this if X isnt 0, else Y doesnt change. - RefChip16Emitter->XOR16ItoR(EAX, GPRStatus.GPRConstVal[Op_X]); - } - else + else //X might be const instead { - MoveLiveRegister(Op_Y, ECX); - CheckLiveRegister(Op_X, false); - RefChip16Emitter->XOR16RtoR(EAX, ECX); + if (CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) + { + dReg = GetLiveRegister(Op_Y); // Write Y back if it was already live as we're about to lose it. + ReAssignLiveRegister(dReg, Op_X); + RefChip16Emitter->XOR16ItoR((X86RegisterType)dReg, GPRStatus.GPRConstVal[Op_X]); + GPRStatus.GPRIsConst[Op_X] = false; + } + else + { + yReg = GetLiveRegister(Op_Y); // Write Y back if it was already live as we're about to lose it. + dReg = GetLiveRegister(Op_X); + RefChip16Emitter->XOR16RtoR((X86RegisterType)dReg, (X86RegisterType)yReg); + } } - - SetLiveRegister(Op_X); - recTestLogic(); - GPRStatus.GPRIsConst[Op_X] = false; } } break; @@ -1535,68 +2155,69 @@ void RecCPU::recCpuXOR() else if(GPRStatus.GPRConstVal[Op_Z] & 0x8000)RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x80); GPRStatus.GPRIsConst[Op_Z] = true; + return; } else { - if(Op_X == Op_Y) + if (Op_X == Op_Y) { - //FPS_LOG("XOR2 X=Y is 0 setting REG_%d to const %x\n", Op_Z, recOpCode); - RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); - - if(CONST_PROP) - { - GPRStatus.GPRIsConst[Op_Z] = true; - GPRStatus.GPRConstVal[Op_Z] = 0; - ClearLiveRegister(Op_Z, false); - } - else - { -#ifdef REG_CACHING - ClearLiveRegister(0xffff, (Op_Z == GPRStatus.LiveGPRReg) ? false : true); - RefChip16Emitter->XOR16RtoR(EAX, EAX); - SetLiveRegister(Op_Z); -#else - RefChip16Emitter->MOV16ItoM((unsigned int)®_Z, 0); -#endif - } + //If we reached here neither are const + FlushLiveRegister(Op_Z, false); //XORing itself will zero the register, so we can make it a const. + GPRStatus.GPRIsConst[Op_Z] = true; + GPRStatus.GPRConstVal[Op_Z] = 0; + RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); + return; } else { - CPU_LOG("XOR2 X %d, Y %d X = %x Y = %x\n", GPRStatus.GPRIsConst[Op_X], GPRStatus.GPRIsConst[Op_Y], GPRStatus.GPRConstVal[Op_X], GPRStatus.GPRConstVal[Op_Y]); - if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) + if (CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) { - CPU_LOG("XOR2 Y Const Opt\n"); - CheckLiveRegister(Op_X, (Op_X == Op_Z) ? false : true); // Write X back if it was already live as we're about to lose it (unless X == Z). - if(GPRStatus.GPRConstVal[Op_Y] != 0) //Only do this if Y isnt 0, else X doesnt change. - RefChip16Emitter->XOR16ItoR(EAX, GPRStatus.GPRConstVal[Op_Y]); + //If we hit here, X wasnt const + dReg = GetLiveRegister(Op_X); + ReAssignLiveRegister(dReg, Op_Z); + RefChip16Emitter->XOR16ItoR((X86RegisterType)dReg, GPRStatus.GPRConstVal[Op_Y]); } - else if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) - { - CPU_LOG("XOR2 X Const Opt\n"); - CheckLiveRegister(Op_Y, (Op_Y == Op_Z) ? false : true); // Write Y back if it was already live as we're about to lose it (unless Y == Z). - if(GPRStatus.GPRConstVal[Op_X] != 0) //Only do this if X isnt 0, else Y doesnt change. - RefChip16Emitter->XOR16ItoR(EAX, GPRStatus.GPRConstVal[Op_X]); - } - else + else //X might be const instead { - MoveLiveRegister(Op_Y, ECX); - CheckLiveRegister(Op_X, (Op_X == Op_Z) ? false : true); // Write X back if it was already live as we're about to lose it (unless X == Z). - RefChip16Emitter->XOR16RtoR(EAX, ECX); + + if (CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) + { + dReg = GetLiveRegister(Op_Y); + ReAssignLiveRegister(dReg, Op_Z); + RefChip16Emitter->XOR16ItoR((X86RegisterType)dReg, GPRStatus.GPRConstVal[Op_X]); + + } + else + { + dReg = GetLiveRegister(Op_X); + yReg = GetLiveRegister(Op_Y); + ReAssignLiveRegister(dReg, Op_Z); + RefChip16Emitter->XOR16RtoR((X86RegisterType)dReg, (X86RegisterType)yReg); + } } - - recTestLogic(); - SetLiveRegister(Op_Z); - GPRStatus.GPRIsConst[Op_Z] = false; } + GPRStatus.GPRIsConst[Op_Z] = false; } break; default: + FlushLiveRegisters(true); FlushConstRegisters(true); RefChip16Emitter->MOV32ItoM((unsigned int)&OpCode, recOpCode); + RefChip16Emitter->MOV32ItoM((unsigned int)&PC, PC); RefChip16Emitter->CALL(CpuXOR); + return; break; } + recTestLogic((X86RegisterType)dReg); + if (yIsTemp == true) + { + FlushLiveRegister(0xfffd, false); + } + if (xTemp >= 0) + FlushLiveRegister(0xfffe, false); + + GPRStatus.LiveGPRReg[dReg].isdirty = true; } void RecCPU::recMULCheckCarry() @@ -1606,10 +2227,14 @@ void RecCPU::recMULCheckCarry() RefChip16Emitter->x86SetJ32( j32Ptr[0] ); //Return from skipping carry flag. } - +//Make sure you clear needed register void RecCPU::recCpuMul() { - + int xReg = -1; + int yReg = -1; + int xTemp = -1; + int dReg = -1; + bool yIsTemp = false; //CPU_LOG("MUL Recompiling %x from PC %x\n", recOpCode, PC-4); RefChip16Emitter->AND16ItoM((unsigned int)&Flag._u16, ~0x86); //Clear Carry Flag @@ -1631,6 +2256,7 @@ void RecCPU::recCpuMul() else if(GPRStatus.GPRConstVal[Op_X] & 0x8000) flags |= 0x80; RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, flags); + return; } else { @@ -1643,28 +2269,30 @@ void RecCPU::recCpuMul() { GPRStatus.GPRIsConst[Op_X] = true; GPRStatus.GPRConstVal[Op_X] = 0; - ClearLiveRegister(Op_X, false); + FlushLiveRegister(Op_X, false); } else { #ifdef REG_CACHING - ClearLiveRegister(0xffff, (Op_X == GPRStatus.LiveGPRReg) ? false : true); - RefChip16Emitter->XOR16RtoR(EAX, EAX); - SetLiveRegister(Op_X); + dReg = GetLiveRegister(Op_X); + RefChip16Emitter->XOR16RtoR((X86RegisterType)dReg, (X86RegisterType)dReg); #else RefChip16Emitter->MOV16ItoM((unsigned int)®_X, 0); #endif } + return; } else { - RefChip16Emitter->MOV16ItoR(ECX, IMMEDIATE); - CheckLiveRegister(Op_X, false); - RefChip16Emitter->MUL16RtoEAX(ECX); + yReg = GetLiveRegister(0xfffd, true); + SetupMulDivSrcRegister(Op_X, 0xfffd, false); + yReg = GetLiveRegister(0xfffd, true); //Do this again in case it moved. + dReg = GetLiveRegister(Op_X); //Should return EAX, in theory. + yIsTemp = true; + RefChip16Emitter->MOV16ItoR((X86RegisterType)yReg, IMMEDIATE); + RefChip16Emitter->MUL16RtoEAX((X86RegisterType)yReg); recMULCheckCarry(); - SetLiveRegister(Op_X); - recTestLogic(); } } break; @@ -1682,6 +2310,7 @@ void RecCPU::recCpuMul() else if(GPRStatus.GPRConstVal[Op_X] & 0x8000) flags |= 0x80; RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, flags); + return; } else { @@ -1689,25 +2318,39 @@ void RecCPU::recCpuMul() if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) { if(GPRStatus.GPRConstVal[Op_Y] == 1) CPU_LOG("MUL 2 Y 1\n"); - RefChip16Emitter->MOV16ItoR(ECX, GPRStatus.GPRConstVal[Op_Y]); + if (GPRStatus.GPRConstVal[Op_Y] == 0) { + FlushLiveRegister(Op_X, false); + RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); + GPRStatus.GPRConstVal[Op_X] = 0; + GPRStatus.GPRIsConst[Op_X] = true; + return; + } + yReg = GetLiveRegister(Op_Y, true); + yIsTemp = true; + RefChip16Emitter->MOV16ItoR((X86RegisterType)yReg, GPRStatus.GPRConstVal[Op_Y]); } - else MoveLiveRegister(Op_Y, ECX); + else yReg = GetLiveRegister(Op_Y); if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) { if(GPRStatus.GPRConstVal[Op_X] == 1) CPU_LOG("MUL 2 X 1\n"); - ClearLiveRegister(0xffff, true); - RefChip16Emitter->MOV16ItoR(EAX, GPRStatus.GPRConstVal[Op_X]); + if (GPRStatus.GPRConstVal[Op_X] == 0) { + RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); + GPRStatus.GPRConstVal[Op_X] = 0; + GPRStatus.GPRIsConst[Op_X] = true; + return; + } + dReg = GetLiveRegister(Op_X, true); + RefChip16Emitter->MOV16ItoR((X86RegisterType)dReg, GPRStatus.GPRConstVal[Op_X]); } - else CheckLiveRegister(Op_X, false); + else dReg = GetLiveRegister(Op_X); - RefChip16Emitter->MUL16RtoEAX(ECX); + SetupMulDivSrcRegister(Op_X, Op_Y, false); + yReg = GetLiveRegister(Op_Y); //Make sure we're pointing at the right registers again + dReg = GetLiveRegister(Op_X); + RefChip16Emitter->MUL16RtoEAX((X86RegisterType)yReg); recMULCheckCarry(); - //RefChip16Emitter->MOV16RtoM((unsigned int)®_X, EAX); - GPRStatus.GPRIsConst[Op_X] = false; - SetLiveRegister(Op_X); - recTestLogic(); - + GPRStatus.GPRIsConst[Op_X] = false; } break; //Z = X * Y [c,z,n] @@ -1725,43 +2368,78 @@ void RecCPU::recCpuMul() RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, flags); GPRStatus.GPRIsConst[Op_Z] = true; + return; } else { CPU_LOG("MUL2 X %d, Y %d X = %x Y = %x\n", GPRStatus.GPRIsConst[Op_X], GPRStatus.GPRIsConst[Op_Y], GPRStatus.GPRConstVal[Op_X], GPRStatus.GPRConstVal[Op_Y]); - if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) + if (CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) { - if(GPRStatus.GPRConstVal[Op_Y] == 1) CPU_LOG("MUL 3 Y 1\n"); - RefChip16Emitter->MOV16ItoR(ECX, GPRStatus.GPRConstVal[Op_Y]); + if (GPRStatus.GPRConstVal[Op_Y] == 1) CPU_LOG("MUL 3 Y 1\n"); + if (GPRStatus.GPRConstVal[Op_Y] == 0) { + FlushLiveRegister(Op_Z, false); + RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); + GPRStatus.GPRConstVal[Op_Z] = 0; + GPRStatus.GPRIsConst[Op_Z] = true; + return; + } + yReg = GetLiveRegister(Op_Y, true); + yIsTemp = true; + RefChip16Emitter->MOV16ItoR((X86RegisterType)yReg, GPRStatus.GPRConstVal[Op_Y]); } - else MoveLiveRegister(Op_Y, ECX); + else yReg = GetLiveRegister(Op_Y); - if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) + if (CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) { - if(GPRStatus.GPRConstVal[Op_X] == 1) CPU_LOG("MUL 3 X 1\n"); - ClearLiveRegister(0xffff, (GPRStatus.LiveGPRReg == Op_Z) ? false : true); - RefChip16Emitter->MOV16ItoR(EAX, GPRStatus.GPRConstVal[Op_X]); + if (GPRStatus.GPRConstVal[Op_X] == 1) CPU_LOG("MUL 3 X 1\n"); + if (GPRStatus.GPRConstVal[Op_X] == 0) { + FlushLiveRegister(Op_Z, false); + RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); + GPRStatus.GPRConstVal[Op_Z] = 0; + GPRStatus.GPRIsConst[Op_Z] = true; + return; + } + dReg = GetLiveRegister(Op_X, true); + RefChip16Emitter->MOV16ItoR((X86RegisterType)dReg, GPRStatus.GPRConstVal[Op_X]); } - else CheckLiveRegister(Op_X, (Op_X == Op_Z) ? false : true); + else dReg = GetLiveRegister(Op_X); - RefChip16Emitter->MUL16RtoEAX(ECX); - + SetupMulDivSrcRegister(Op_X, Op_Y, false); + + yReg = GetLiveRegister(Op_Y); //Make sure we're pointing at the right registers again + dReg = GetLiveRegister(Op_X); + if (Op_Y == Op_Z) + { + MoveLiveRegister((X86RegisterType)dReg, (X86RegisterType)yReg, true); + yIsTemp = false; + } + AssignLiveRegister(Op_Z, dReg); + RefChip16Emitter->MUL16RtoEAX((X86RegisterType)yReg); recMULCheckCarry(); - - SetLiveRegister(Op_Z); GPRStatus.GPRIsConst[Op_Z] = false; - recTestLogic(); } break; default: - ClearLiveRegister(0xffff, true); + FlushLiveRegisters(true); + FlushConstRegisters(true); RefChip16Emitter->MOV32ItoM((unsigned int)&OpCode, recOpCode); + RefChip16Emitter->MOV32ItoM((unsigned int)&PC, PC); RefChip16Emitter->CALL(CpuMul); return; break; } + recTestLogic((X86RegisterType)dReg); + if (yIsTemp == true) + { + FlushLiveRegister(GPRStatus.LiveGPRReg[yReg].gprreg, false); + } + if (xTemp >= 0) + FlushLiveRegister(0xfffe, false); + + ToggleLockRegister(EDX, false); + GPRStatus.LiveGPRReg[dReg].isdirty = true; } void RecCPU::recDIVCheckCarry() @@ -1775,12 +2453,17 @@ void RecCPU::recDIVCheckCarry() } +//Make sure you clear needed registers void RecCPU::recCpuDiv() { + int xReg = -1; + int yReg = -1; + int xTemp = -1; + int dReg = -1; + bool yIsTemp = false; //CPU_LOG("DIV Recompiling %x from PC %x\n", recOpCode, PC-4); //DIV uses EDX and EAX, if anything is in EDX, it could screw things up - RefChip16Emitter->XOR16RtoR(EDX, EDX); RefChip16Emitter->AND16ItoM((unsigned int)&Flag._u16, ~0x86); //Clear Carry Flag switch((recOpCode >> 16) & 0xf) @@ -1804,18 +2487,22 @@ void RecCPU::recCpuDiv() RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, flags); GPRStatus.GPRIsConst[Op_X] = true; + return; } else { if(IMMEDIATE == 1) CPU_LOG("DIV 1 IMM 1\n"); - CheckLiveRegister(Op_X, false); - RefChip16Emitter->MOV16ItoR(ECX, IMMEDIATE); - RefChip16Emitter->DIV16RtoEAX(ECX); + yReg = GetLiveRegister(0xfffe, true); + yIsTemp = true; + RefChip16Emitter->MOV16ItoR((X86RegisterType)yReg, IMMEDIATE); + SetupMulDivSrcRegister(Op_X, 0xfffe, false); + yReg = ECX; + dReg = EAX; + + + RefChip16Emitter->DIV16RtoEAX((X86RegisterType)yReg); recDIVCheckCarry(); - - SetLiveRegister(Op_X); - recTestLogic(); } break; //X = X / Y [c,z,n] @@ -1836,6 +2523,7 @@ void RecCPU::recCpuDiv() else if(GPRStatus.GPRConstVal[Op_X] & 0x8000) flags |= 0x80; RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, flags); + return; } else { @@ -1845,18 +2533,18 @@ void RecCPU::recCpuDiv() { GPRStatus.GPRIsConst[Op_X] = true; GPRStatus.GPRConstVal[Op_X] = 1; - ClearLiveRegister(Op_X, false); + FlushLiveRegister(Op_X, false); } else { #ifdef REG_CACHING - ClearLiveRegister(0xffff, (Op_X == GPRStatus.LiveGPRReg) ? false : true); - RefChip16Emitter->MOV16ItoR(EAX, 1); - SetLiveRegister(Op_X); + xReg = GetLiveRegister(Op_X, true); + RefChip16Emitter->MOV16ItoR((X86RegisterType)xReg, 1); #else RefChip16Emitter->MOV16ItoM((unsigned int)®_X, 1); #endif } + return; } else { @@ -1864,25 +2552,29 @@ void RecCPU::recCpuDiv() if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) { if(GPRStatus.GPRConstVal[Op_Y] == 1) CPU_LOG("DIV 2 Y 1\n"); - RefChip16Emitter->MOV16ItoR(ECX, GPRStatus.GPRConstVal[Op_Y]); + yReg = GetLiveRegister(Op_Y, true); + yIsTemp = true; + RefChip16Emitter->MOV16ItoR((X86RegisterType)yReg, GPRStatus.GPRConstVal[Op_Y]); } - else MoveLiveRegister(Op_Y, ECX); + else yReg = GetLiveRegister(Op_Y); if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) { if(GPRStatus.GPRConstVal[Op_X] == 1) CPU_LOG("DIV 2 X 1\n"); - ClearLiveRegister(0xffff, true); - RefChip16Emitter->MOV16ItoR(EAX, GPRStatus.GPRConstVal[Op_X]); - SetLiveRegister(Op_X); + xReg = GetLiveRegister(Op_X, true); + RefChip16Emitter->MOV16ItoR((X86RegisterType)xReg, GPRStatus.GPRConstVal[Op_X]); } - else CheckLiveRegister(Op_X, false); + else xReg = GetLiveRegister(Op_X); - RefChip16Emitter->DIV16RtoEAX(ECX); + SetupMulDivSrcRegister(Op_X, Op_Y, false); + yReg = ECX; + xReg = EAX; + dReg = xReg; + + RefChip16Emitter->DIV16RtoEAX((X86RegisterType)yReg); recDIVCheckCarry(); GPRStatus.GPRIsConst[Op_X] = false; - SetLiveRegister(Op_X); - recTestLogic(); } } break; @@ -1905,6 +2597,7 @@ void RecCPU::recCpuDiv() RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, flags); GPRStatus.GPRIsConst[Op_Z] = true; + return; } else { @@ -1914,82 +2607,113 @@ void RecCPU::recCpuDiv() { GPRStatus.GPRIsConst[Op_Z] = true; GPRStatus.GPRConstVal[Op_Z] = 1; - ClearLiveRegister(Op_Z, false); + FlushLiveRegister(Op_Z, false); } else { #ifdef REG_CACHING - ClearLiveRegister(0xffff, (Op_X == GPRStatus.LiveGPRReg) ? false : true); - RefChip16Emitter->MOV16ItoR(EAX, 1); - SetLiveRegister(Op_Z); + dReg = GetLiveRegister(Op_Z, true); + RefChip16Emitter->MOV16ItoR((X86RegisterType)dReg, 1); #else RefChip16Emitter->MOV16ItoM((unsigned int)®_Z, 1); #endif } + return; } else { - CPU_LOG("DIV3 X %d, Y %d X = %x Y = %x\n", GPRStatus.GPRIsConst[Op_X], GPRStatus.GPRIsConst[Op_Y], GPRStatus.GPRConstVal[Op_X], GPRStatus.GPRConstVal[Op_Y]); + CPU_LOG("DIV2 X %d, Y %d X = %x Y = %x\n", GPRStatus.GPRIsConst[Op_X], GPRStatus.GPRIsConst[Op_Y], GPRStatus.GPRConstVal[Op_X], GPRStatus.GPRConstVal[Op_Y]); if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) { - if(GPRStatus.GPRConstVal[Op_Y] == 1) CPU_LOG("DIV 3 Y 1\n"); - RefChip16Emitter->MOV16ItoR(ECX, GPRStatus.GPRConstVal[Op_Y]); + if(GPRStatus.GPRConstVal[Op_Y] == 1) CPU_LOG("DIV 2 Y 1\n"); + yReg = GetLiveRegister(Op_Y, true); + yIsTemp = true; + RefChip16Emitter->MOV16ItoR((X86RegisterType)yReg, GPRStatus.GPRConstVal[Op_Y]); } - else MoveLiveRegister(Op_Y, ECX); + else yReg = GetLiveRegister(Op_Y); if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) { - if(GPRStatus.GPRConstVal[Op_X] == 1) CPU_LOG("DIV 3 X 1\n"); - ClearLiveRegister(0xffff, (GPRStatus.LiveGPRReg == Op_Z) ? false : true); - RefChip16Emitter->MOV16ItoR(EAX, GPRStatus.GPRConstVal[Op_X]); - + if(GPRStatus.GPRConstVal[Op_X] == 1) CPU_LOG("DIV 2 X 1\n"); + xReg = GetLiveRegister(Op_X, true); + RefChip16Emitter->MOV16ItoR((X86RegisterType)xReg, GPRStatus.GPRConstVal[Op_X]); } - else CheckLiveRegister(Op_X, (Op_X == Op_Z) ? false : true); + else xReg = GetLiveRegister(Op_X); - RefChip16Emitter->DIV16RtoEAX(ECX); - recDIVCheckCarry(); + SetupMulDivSrcRegister(Op_X, Op_Y, false); + yReg = ECX; + xReg = EAX; + FlushLiveRegister(Op_X, GPRStatus.GPRIsConst[Op_X] ? false : true); + RefChip16Emitter->DIV16RtoEAX((X86RegisterType)yReg); + + recDIVCheckCarry(); + ReAssignLiveRegister(EAX, Op_Z); GPRStatus.GPRIsConst[Op_Z] = false; - SetLiveRegister(Op_Z); - recTestLogic(); + dReg = EAX; } } break; - //X = X % IMM [z,n] - case 0x6: + //X = X MOD IMM [z,n] + case 0x3: if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) { int flags = 0; + short TempResult = 0; - GPRStatus.GPRConstVal[Op_X] = (short)GPRStatus.GPRConstVal[Op_X] % (short)IMMEDIATE; + TempResult = (short)GPRStatus.GPRConstVal[Op_X] % (short)IMMEDIATE; + if((GPRStatus.GPRConstVal[Op_X] & 0x8000) ^ (IMMEDIATE & 0x8000)) GPRStatus.GPRConstVal[Op_X] = TempResult + IMMEDIATE; + else GPRStatus.GPRConstVal[Op_X] = TempResult; + if(GPRStatus.GPRConstVal[Op_X] == 0) flags |= 0x4; else if(GPRStatus.GPRConstVal[Op_X] & 0x8000) flags |= 0x80; RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, flags); GPRStatus.GPRIsConst[Op_X] = true; + return; } else { - CheckLiveRegister(Op_X, false); - RefChip16Emitter->MOV16ItoR(ECX, IMMEDIATE); - RefChip16Emitter->DIV16RtoEAX(ECX); - RefChip16Emitter->MOV16RtoR(EAX, EDX); - recTestLogic(); + yReg = GetLiveRegister(0xfffe, true); + yIsTemp = true; + SetupMulDivSrcRegister(Op_X, 0xfffe, true); + yReg = ECX; + dReg = EAX; + + RefChip16Emitter->MOV16ItoR((X86RegisterType)yReg, IMMEDIATE); + RefChip16Emitter->IDIV16RtoEAX((X86RegisterType)yReg); + + RefChip16Emitter->XOR16RtoR((X86RegisterType)dReg, (X86RegisterType)yReg); + RefChip16Emitter->AND16ItoR((X86RegisterType)dReg, 0x8000); + + RefChip16Emitter->CMP16ItoR((X86RegisterType)dReg, 0x8000); + j32Ptr[0] = RefChip16Emitter->JNE32(0); + + RefChip16Emitter->ADD16RtoR(EDX, (X86RegisterType)yReg); + + RefChip16Emitter->x86SetJ32( j32Ptr[0] ); + + RefChip16Emitter->MOV16RtoR((X86RegisterType)dReg, EDX); } break; - //X = X % Y [z,n] - case 0x7: + //X = X MOD Y [z,n] + case 0x4: if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true && GPRStatus.GPRIsConst[Op_Y] == true) { int flags = 0; + short TempResult = 0; - GPRStatus.GPRConstVal[Op_X] = (short)GPRStatus.GPRConstVal[Op_X] % (short)GPRStatus.GPRConstVal[Op_Y]; + TempResult = (short)GPRStatus.GPRConstVal[Op_X] % (short)GPRStatus.GPRConstVal[Op_Y]; + + if((GPRStatus.GPRConstVal[Op_X] & 0x8000) ^ (GPRStatus.GPRConstVal[Op_Y] & 0x8000)) GPRStatus.GPRConstVal[Op_X] = TempResult + (short)GPRStatus.GPRConstVal[Op_Y]; + else GPRStatus.GPRConstVal[Op_X] = TempResult; if(GPRStatus.GPRConstVal[Op_X] == 0) flags |= 0x4; else if(GPRStatus.GPRConstVal[Op_X] & 0x8000) flags |= 0x80; RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, flags); + return; } else { @@ -1999,304 +2723,347 @@ void RecCPU::recCpuDiv() { GPRStatus.GPRIsConst[Op_X] = true; GPRStatus.GPRConstVal[Op_X] = 0; - ClearLiveRegister(Op_X, false); + FlushLiveRegister(Op_X, false); } else { #ifdef REG_CACHING - ClearLiveRegister(0xffff, (Op_X == GPRStatus.LiveGPRReg) ? false : true); - RefChip16Emitter->MOV16ItoR(EAX, 0); - SetLiveRegister(Op_X); + dReg = GetLiveRegister(Op_X, true); + RefChip16Emitter->MOV16ItoR((X86RegisterType)dReg, 0); #else RefChip16Emitter->MOV16ItoM((unsigned int)®_X, 0); #endif } + RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); + return; } else { - if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) + if (CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) { - RefChip16Emitter->MOV16ItoR(ECX, GPRStatus.GPRConstVal[Op_Y]); + if (GPRStatus.GPRConstVal[Op_Y] == 1) CPU_LOG("DIV 2 Y 1\n"); + yReg = GetLiveRegister(Op_Y, true); + yIsTemp = true; + RefChip16Emitter->MOV16ItoR((X86RegisterType)yReg, GPRStatus.GPRConstVal[Op_Y]); } - else MoveLiveRegister(Op_Y, ECX); + else yReg = GetLiveRegister(Op_Y); - if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) + if (CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) { - ClearLiveRegister(0xffff, true); - RefChip16Emitter->MOV16ItoR(EAX, GPRStatus.GPRConstVal[Op_X]); - SetLiveRegister(Op_X); + if (GPRStatus.GPRConstVal[Op_X] == 1) CPU_LOG("DIV 2 X 1\n"); + xReg = GetLiveRegister(Op_X, true); + RefChip16Emitter->MOV16ItoR((X86RegisterType)xReg, GPRStatus.GPRConstVal[Op_X]); } - else CheckLiveRegister(Op_X, false); + else xReg = GetLiveRegister(Op_X); + + SetupMulDivSrcRegister(Op_X, Op_Y, true); + yReg = GetLiveRegister(Op_Y); + xReg = GetLiveRegister(Op_X); + dReg = xReg; + xTemp = GetLiveRegister(0xfffe, true); - RefChip16Emitter->DIV16RtoEAX(ECX); + RefChip16Emitter->MOV16RtoR((X86RegisterType)xTemp, (X86RegisterType)xReg); + RefChip16Emitter->XOR16RtoR((X86RegisterType)xTemp, (X86RegisterType)yReg); + RefChip16Emitter->AND16ItoR((X86RegisterType)xTemp, 0x8000); - RefChip16Emitter->MOV16RtoR(EAX, EDX); + RefChip16Emitter->IDIV16RtoEAX((X86RegisterType)yReg); + + + RefChip16Emitter->CMP16ItoR((X86RegisterType)xTemp, 0x8000); + j32Ptr[0] = RefChip16Emitter->JNE32(0); + + RefChip16Emitter->ADD16RtoR(EDX, (X86RegisterType)yReg); + + RefChip16Emitter->x86SetJ32( j32Ptr[0] ); + + RefChip16Emitter->MOV16RtoR((X86RegisterType)dReg, EDX); GPRStatus.GPRIsConst[Op_X] = false; - SetLiveRegister(Op_X); - recTestLogic(); } } break; - //Z = X % Y [z,n] - case 0x8: + //Z = X MOD Y [z,n] + case 0x5: if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true && GPRStatus.GPRIsConst[Op_Y] == true) { int flags = 0; + short TempResult = 0; - GPRStatus.GPRConstVal[Op_Z] = (short)GPRStatus.GPRConstVal[Op_X] % (short)GPRStatus.GPRConstVal[Op_Y]; + TempResult = (short)GPRStatus.GPRConstVal[Op_X] % (short)GPRStatus.GPRConstVal[Op_Y]; + + if((GPRStatus.GPRConstVal[Op_X] & 0x8000) ^ (GPRStatus.GPRConstVal[Op_Y] & 0x8000)) GPRStatus.GPRConstVal[Op_Z] = TempResult + (short)GPRStatus.GPRConstVal[Op_Y]; + else GPRStatus.GPRConstVal[Op_Z] = TempResult; if(GPRStatus.GPRConstVal[Op_Z] == 0) flags |= 0x4; else if(GPRStatus.GPRConstVal[Op_Z] & 0x8000) flags |= 0x80; RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, flags); GPRStatus.GPRIsConst[Op_Z] = true; + return; } else { - if(Op_X == Op_Y) + if (Op_X == Op_Y) { - if(CONST_PROP) + if (CONST_PROP) { - GPRStatus.GPRIsConst[Op_Z] = true; - GPRStatus.GPRConstVal[Op_Z] = 0; - ClearLiveRegister(Op_Z, false); + GPRStatus.GPRIsConst[Op_X] = true; + GPRStatus.GPRConstVal[Op_X] = 0; + FlushLiveRegister(Op_X, false); } else { #ifdef REG_CACHING - ClearLiveRegister(0xffff, (Op_X == GPRStatus.LiveGPRReg) ? false : true); - RefChip16Emitter->MOV16ItoR(EAX, 0); - SetLiveRegister(Op_Z); + dReg = GetLiveRegister(Op_X, true); + RefChip16Emitter->MOV16ItoR((X86RegisterType)dReg, 0); #else - RefChip16Emitter->MOV16ItoM((unsigned int)®_Z, 0); + RefChip16Emitter->MOV16ItoM((unsigned int)®_X, 0); #endif } + RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); + return; } else { - if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) + if (CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) { - RefChip16Emitter->MOV16ItoR(ECX, GPRStatus.GPRConstVal[Op_Y]); + if (GPRStatus.GPRConstVal[Op_Y] == 1) CPU_LOG("DIV 2 Y 1\n"); + yReg = GetLiveRegister(Op_Y, true); + yIsTemp = true; + RefChip16Emitter->MOV16ItoR((X86RegisterType)yReg, GPRStatus.GPRConstVal[Op_Y]); } - else MoveLiveRegister(Op_Y, ECX); + else yReg = GetLiveRegister(Op_Y); - if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) + if (CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) { - ClearLiveRegister(0xffff, (GPRStatus.LiveGPRReg == Op_Z) ? false : true); - RefChip16Emitter->MOV16ItoR(EAX, GPRStatus.GPRConstVal[Op_X]); - + if (GPRStatus.GPRConstVal[Op_X] == 1) CPU_LOG("DIV 2 X 1\n"); + xReg = GetLiveRegister(Op_X, true); + RefChip16Emitter->MOV16ItoR((X86RegisterType)xReg, GPRStatus.GPRConstVal[Op_X]); } - else CheckLiveRegister(Op_X, (Op_X == Op_Z) ? false : true); + else xReg = GetLiveRegister(Op_X); + + SetupMulDivSrcRegister(Op_X, Op_Y, true); + yReg = GetLiveRegister(Op_Y); + xReg = GetLiveRegister(Op_X); + dReg = xReg; + xTemp = GetLiveRegister(0xfffe, true); + + RefChip16Emitter->MOV16RtoR((X86RegisterType)xTemp, (X86RegisterType)xReg); + RefChip16Emitter->XOR16RtoR((X86RegisterType)xTemp, (X86RegisterType)yReg); + RefChip16Emitter->AND16ItoR((X86RegisterType)xTemp, 0x8000); + FlushLiveRegister(xReg, GPRStatus.GPRIsConst[Op_X] ? false : true); + RefChip16Emitter->IDIV16RtoEAX((X86RegisterType)yReg); + - RefChip16Emitter->DIV16RtoEAX(ECX); - RefChip16Emitter->MOV16RtoR(EAX, EDX); + RefChip16Emitter->CMP16ItoR((X86RegisterType)xTemp, 0x8000); + j32Ptr[0] = RefChip16Emitter->JNE32(0); + + RefChip16Emitter->ADD16RtoR(EDX, (X86RegisterType)yReg); + RefChip16Emitter->x86SetJ32(j32Ptr[0]); + + RefChip16Emitter->MOV16RtoR((X86RegisterType)dReg, EDX); + ReAssignLiveRegister(EAX, Op_Z); GPRStatus.GPRIsConst[Op_Z] = false; - SetLiveRegister(Op_Z); - recTestLogic(); - } + } } break; - //X = X MOD IMM [z,n] - case 0x9: + //X = X % IMM [z,n] + case 0x6: if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) { int flags = 0; - short TempResult = 0; - - TempResult = (short)GPRStatus.GPRConstVal[Op_X] % (short)IMMEDIATE; - - if((GPRStatus.GPRConstVal[Op_X] & 0x8000) ^ (IMMEDIATE & 0x8000)) GPRStatus.GPRConstVal[Op_X] = TempResult + IMMEDIATE; - else GPRStatus.GPRConstVal[Op_X] = TempResult; - + CPU_LOG("X = X REM IMM CONST\n"); + GPRStatus.GPRConstVal[Op_X] = (short)GPRStatus.GPRConstVal[Op_X] % IMMEDIATE; + CPU_LOG("Result = %d\n", (short)GPRStatus.GPRConstVal[Op_X]); if(GPRStatus.GPRConstVal[Op_X] == 0) flags |= 0x4; else if(GPRStatus.GPRConstVal[Op_X] & 0x8000) flags |= 0x80; RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, flags); - GPRStatus.GPRIsConst[Op_X] = true; + return; } else { - CheckLiveRegister(Op_X, false); - RefChip16Emitter->MOV16ItoR(ECX, IMMEDIATE); - RefChip16Emitter->DIV16RtoEAX(ECX); - CheckLiveRegister(Op_X, false); - RefChip16Emitter->XOR16RtoR(EAX, ECX); - RefChip16Emitter->AND16ItoR(EAX, 0x8000); + CPU_LOG("X = X REM IMM"); + //FlushLiveRegisters(true); + xTemp = GetLiveRegister(0xfffe, true); + SetupMulDivSrcRegister(Op_X, 0xfffe, true); + xTemp = ECX; - RefChip16Emitter->CMP16ItoR(EAX, 0x8000); - j32Ptr[0] = RefChip16Emitter->JNE32(0); + RefChip16Emitter->MOV16ItoR((X86RegisterType)xTemp, IMMEDIATE); - RefChip16Emitter->ADD16RtoR(EDX, ECX); + RefChip16Emitter->x86SetJ32(j32Ptr[1]); - RefChip16Emitter->x86SetJ32( j32Ptr[0] ); + RefChip16Emitter->IDIV16RtoEAX((X86RegisterType)xTemp); + GPRStatus.GPRIsConst[Op_X] = false; - RefChip16Emitter->MOV16RtoR(EAX, EDX); - SetLiveRegister(Op_X); //Shouldn't be needed, but just to be safe incase the moon aligns with alpha centuri - recTestLogic(); + ReAssignLiveRegister(EDX, Op_X); + dReg = EDX; } break; - //X = X MOD Y [z,n] - case 0xA: + //X = X % Y [z,n] + case 0x7: if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true && GPRStatus.GPRIsConst[Op_Y] == true) { int flags = 0; - short TempResult = 0; - TempResult = (short)GPRStatus.GPRConstVal[Op_X] % (short)GPRStatus.GPRConstVal[Op_Y]; - - if((GPRStatus.GPRConstVal[Op_X] & 0x8000) ^ (GPRStatus.GPRConstVal[Op_Y] & 0x8000)) GPRStatus.GPRConstVal[Op_X] = TempResult + (short)GPRStatus.GPRConstVal[Op_Y]; - else GPRStatus.GPRConstVal[Op_X] = TempResult; + GPRStatus.GPRConstVal[Op_X] = (short)GPRStatus.GPRConstVal[Op_X] % (short)GPRStatus.GPRConstVal[Op_Y]; if(GPRStatus.GPRConstVal[Op_X] == 0) flags |= 0x4; else if(GPRStatus.GPRConstVal[Op_X] & 0x8000) flags |= 0x80; RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, flags); - GPRStatus.GPRIsConst[Op_X] = true; + return; } - else - { - if(Op_X == Op_Y) + else { + if (Op_X == Op_Y) { - if(CONST_PROP) + if (CONST_PROP) { GPRStatus.GPRIsConst[Op_X] = true; - GPRStatus.GPRConstVal[Op_X] = 0; - ClearLiveRegister(Op_X, false); + GPRStatus.GPRConstVal[Op_X] = 0; + FlushLiveRegister(Op_X, false); } else { #ifdef REG_CACHING - ClearLiveRegister(0xffff, (Op_X == GPRStatus.LiveGPRReg) ? false : true); - RefChip16Emitter->MOV16ItoR(EAX, 0); - SetLiveRegister(Op_X); + xReg = GetLiveRegister(Op_X, true); + RefChip16Emitter->MOV16ItoR((X86RegisterType)xReg, 0); #else RefChip16Emitter->MOV16ItoM((unsigned int)®_X, 0); #endif } + RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); + return; } else { - if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) + if (CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) { - RefChip16Emitter->MOV16ItoR(ECX, GPRStatus.GPRConstVal[Op_Y]); + if (GPRStatus.GPRConstVal[Op_Y] == 1) CPU_LOG("DIV 2 Y 1\n"); + yReg = GetLiveRegister(Op_Y, true); + yIsTemp = true; + RefChip16Emitter->MOV16ItoR((X86RegisterType)yReg, GPRStatus.GPRConstVal[Op_Y]); } - else MoveLiveRegister(Op_Y, ECX); + else yReg = GetLiveRegister(Op_Y); - if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) + if (CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) { - ClearLiveRegister(0xffff, true); - RefChip16Emitter->MOV16ItoR(EAX, GPRStatus.GPRConstVal[Op_X]); - SetLiveRegister(Op_X); + if (GPRStatus.GPRConstVal[Op_X] == 1) CPU_LOG("DIV 2 X 1\n"); + xReg = GetLiveRegister(Op_X, true); + RefChip16Emitter->MOV16ItoR((X86RegisterType)xReg, GPRStatus.GPRConstVal[Op_X]); } - else CheckLiveRegister(Op_X, false); - - RefChip16Emitter->DIV16RtoEAX(ECX); - CheckLiveRegister(Op_X, false); - RefChip16Emitter->XOR16RtoR(EAX, ECX); - RefChip16Emitter->AND16ItoR(EAX, 0x8000); + else xReg = GetLiveRegister(Op_X); - RefChip16Emitter->CMP16ItoR(EAX, 0x8000); - j32Ptr[0] = RefChip16Emitter->JNE32(0); - - RefChip16Emitter->ADD16ItoR(EDX, ECX); + SetupMulDivSrcRegister(Op_X, Op_Y, true); + yReg = ECX; + xReg = EAX; - RefChip16Emitter->x86SetJ32( j32Ptr[0] ); + RefChip16Emitter->IDIV16RtoEAX((X86RegisterType)yReg); - RefChip16Emitter->MOV16RtoR(EAX, EDX); GPRStatus.GPRIsConst[Op_X] = false; - SetLiveRegister(Op_X); //Shouldn't be needed, but just to be safe incase the moon aligns with alpha centuri - recTestLogic(); - } + FlushLiveRegister(Op_X, false); + ReAssignLiveRegister(EDX, Op_X); + dReg = EDX; + } } break; - //Z = X MOD Y [z,n] - case 0xB: + //Z = X % Y [z,n] + case 0x8: if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true && GPRStatus.GPRIsConst[Op_Y] == true) { int flags = 0; - short TempResult = 0; - TempResult = (short)GPRStatus.GPRConstVal[Op_X] % (short)GPRStatus.GPRConstVal[Op_Y]; - - if((GPRStatus.GPRConstVal[Op_X] & 0x8000) ^ (GPRStatus.GPRConstVal[Op_Y] & 0x8000)) GPRStatus.GPRConstVal[Op_Z] = TempResult + (short)GPRStatus.GPRConstVal[Op_Y]; - else GPRStatus.GPRConstVal[Op_Z] = TempResult; + GPRStatus.GPRConstVal[Op_Z] = (short)GPRStatus.GPRConstVal[Op_X] % (short)GPRStatus.GPRConstVal[Op_Y]; if(GPRStatus.GPRConstVal[Op_Z] == 0) flags |= 0x4; else if(GPRStatus.GPRConstVal[Op_Z] & 0x8000) flags |= 0x80; RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, flags); GPRStatus.GPRIsConst[Op_Z] = true; + return; } else { - if(Op_X == Op_Y) + if (Op_X == Op_Y) { - if(CONST_PROP) + if (CONST_PROP) { - GPRStatus.GPRIsConst[Op_Z] = true; - GPRStatus.GPRConstVal[Op_Z] = 0; - ClearLiveRegister(Op_Z, false); + GPRStatus.GPRIsConst[Op_X] = true; + GPRStatus.GPRConstVal[Op_X] = 0; + FlushLiveRegister(Op_X, false); } else { #ifdef REG_CACHING - ClearLiveRegister(0xffff, (Op_X == GPRStatus.LiveGPRReg) ? false : true); - RefChip16Emitter->MOV16ItoR(EAX, 0); - SetLiveRegister(Op_Z); + xReg = GetLiveRegister(Op_X, true); + RefChip16Emitter->MOV16ItoR((X86RegisterType)xReg, 0); #else - RefChip16Emitter->MOV16ItoM((unsigned int)®_Z, 0); + RefChip16Emitter->MOV16ItoM((unsigned int)®_X, 0); #endif } + RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, 0x4); + return; } else { - if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) + if (CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) { - RefChip16Emitter->MOV16ItoR(ECX, GPRStatus.GPRConstVal[Op_Y]); + if (GPRStatus.GPRConstVal[Op_Y] == 1) CPU_LOG("DIV 2 Y 1\n"); + yReg = GetLiveRegister(Op_Y, true); + yIsTemp = true; + RefChip16Emitter->MOV16ItoR((X86RegisterType)yReg, GPRStatus.GPRConstVal[Op_Y]); } - else MoveLiveRegister(Op_Y, ECX); + else yReg = GetLiveRegister(Op_Y); - if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) + if (CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) { - ClearLiveRegister(0xffff, (GPRStatus.LiveGPRReg == Op_Z) ? false : true); - RefChip16Emitter->MOV16ItoR(EAX, GPRStatus.GPRConstVal[Op_X]); - + if (GPRStatus.GPRConstVal[Op_X] == 1) CPU_LOG("DIV 2 X 1\n"); + xReg = GetLiveRegister(Op_X, true); + RefChip16Emitter->MOV16ItoR((X86RegisterType)xReg, GPRStatus.GPRConstVal[Op_X]); } - else CheckLiveRegister(Op_X, (Op_X == Op_Z) ? false : true); - - RefChip16Emitter->DIV16RtoEAX(ECX); - CheckLiveRegister(Op_X, false); - RefChip16Emitter->XOR16RtoR(EAX, ECX); - RefChip16Emitter->AND16ItoR(EAX, 0x8000); - - RefChip16Emitter->CMP16ItoR(EAX, 0x8000); - j32Ptr[0] = RefChip16Emitter->JNE32(0); - - RefChip16Emitter->ADD16ItoR(EDX, ECX); + else xReg = GetLiveRegister(Op_X); - RefChip16Emitter->x86SetJ32( j32Ptr[0] ); + SetupMulDivSrcRegister(Op_X, Op_Y, true); + yReg = ECX; + xReg = EAX; + FlushLiveRegister(Op_X, GPRStatus.GPRIsConst[Op_X] ? false : true); + RefChip16Emitter->IDIV16RtoEAX((X86RegisterType)yReg); - RefChip16Emitter->MOV16RtoR(EAX, EDX); - GPRStatus.GPRIsConst[Op_Z] = false; - SetLiveRegister(Op_Z); //Really needed this time ;) - recTestLogic(); - } + GPRStatus.GPRIsConst[Op_X] = false; + ReAssignLiveRegister(EDX, Op_Z); + dReg = EDX; + } } break; default: - ClearLiveRegister(0xffff, true); + FlushLiveRegisters(true); FlushConstRegisters(true); RefChip16Emitter->MOV32ItoM((unsigned int)&OpCode, recOpCode); + RefChip16Emitter->MOV32ItoM((unsigned int)&PC, PC); RefChip16Emitter->CALL(CpuDiv); + return; break; } - + recTestLogic((X86RegisterType)dReg); + if (yIsTemp == true) + { + FlushLiveRegister(GPRStatus.LiveGPRReg[yReg].gprreg, false); + } + if (xTemp >= 0) + FlushLiveRegister(0xfffe, false); + + ToggleLockRegister(EDX, false); + GPRStatus.LiveGPRReg[dReg].isdirty = true; } void RecCPU::recCpuShift() { //CPU_LOG("SHIFT Recompiling %x from PC %x\n", recOpCode, PC-4); - + int dReg = -1; + int xReg = -1; + int yReg = -1; + bool yIsTemp = false; + int xTemp = -1; + RefChip16Emitter->AND16ItoM((unsigned int)&Flag._u16, ~0x84); switch(((recOpCode >> 16) & 0xf)) @@ -2316,9 +3083,8 @@ void RecCPU::recCpuShift() { if((recOpCode & 0xf) != 0) { - CheckLiveRegister(Op_X, false); - RefChip16Emitter->SHL16ItoR(EAX, (recOpCode & 0xf)); - SetLiveRegister(Op_X); + dReg = GetLiveRegister(Op_X); + RefChip16Emitter->SHL16ItoR((X86RegisterType)dReg, (recOpCode & 0xf)); } } break; @@ -2337,9 +3103,8 @@ void RecCPU::recCpuShift() { if((recOpCode & 0xf) != 0) { - CheckLiveRegister(Op_X, false); - RefChip16Emitter->SHR16ItoR(EAX, (recOpCode & 0xf)); - SetLiveRegister(Op_X); + dReg = GetLiveRegister(Op_X); + RefChip16Emitter->SHR16ItoR((X86RegisterType)dReg, (recOpCode & 0xf)); } } break; @@ -2359,9 +3124,8 @@ void RecCPU::recCpuShift() { if((recOpCode & 0xf) != 0) { - CheckLiveRegister(Op_X, false); - RefChip16Emitter->SAR16ItoR(EAX, (recOpCode & 0xf)); - SetLiveRegister(Op_X); + dReg = GetLiveRegister(Op_X); + RefChip16Emitter->SAR16ItoR((X86RegisterType)dReg, (recOpCode & 0xf)); } } break; @@ -2381,21 +3145,29 @@ void RecCPU::recCpuShift() CPU_LOG("SHFT1 X %d, Y %d X = %x Y = %x\n", GPRStatus.GPRIsConst[Op_X], GPRStatus.GPRIsConst[Op_Y], GPRStatus.GPRConstVal[Op_X], GPRStatus.GPRConstVal[Op_Y]); if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) { - RefChip16Emitter->MOV16ItoR(ECX, GPRStatus.GPRConstVal[Op_Y]); + yReg = GetLiveRegister(0xfffd, true); + yIsTemp = true; + RefChip16Emitter->MOV16ItoR((X86RegisterType)yReg, GPRStatus.GPRConstVal[Op_Y]); } - else MoveLiveRegister(Op_Y, ECX); + else yReg = GetLiveRegister(Op_Y); + + MoveLiveRegister(ECX, (X86RegisterType)yReg, true); + + yReg = GetLiveRegister(yIsTemp ? 0xfffd : Op_Y); if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) { - ClearLiveRegister(0xffff, true); - RefChip16Emitter->MOV16ItoR(EAX, GPRStatus.GPRConstVal[Op_X]); - SetLiveRegister(Op_X); + dReg = GetLiveRegister(Op_X, true); + RefChip16Emitter->MOV16ItoR((X86RegisterType)dReg, GPRStatus.GPRConstVal[Op_X]); } - else CheckLiveRegister(Op_X, false); - - RefChip16Emitter->SHL16CLtoR(EAX); + else dReg = GetLiveRegister(Op_X); + + MoveLiveRegister(EAX, (X86RegisterType)dReg, true); + + dReg = GetLiveRegister(Op_X); + + RefChip16Emitter->SHL16CLtoR((X86RegisterType)dReg); //RefChip16Emitter->MOV16RtoM((unsigned int)®_X, EAX); - SetLiveRegister(Op_X); GPRStatus.GPRIsConst[Op_X] = false; } break; @@ -2414,23 +3186,31 @@ void RecCPU::recCpuShift() else { CPU_LOG("SHFT2 X %d, Y %d X = %x Y = %x\n", GPRStatus.GPRIsConst[Op_X], GPRStatus.GPRIsConst[Op_Y], GPRStatus.GPRConstVal[Op_X], GPRStatus.GPRConstVal[Op_Y]); - if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) + if (CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) { - RefChip16Emitter->MOV16ItoR(ECX, GPRStatus.GPRConstVal[Op_Y]); + yReg = GetLiveRegister(0xfffd, true); + yIsTemp = true; + RefChip16Emitter->MOV16ItoR((X86RegisterType)yReg, GPRStatus.GPRConstVal[Op_Y]); } - else MoveLiveRegister(Op_Y, ECX); + else yReg = GetLiveRegister(Op_Y); - if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) + MoveLiveRegister(ECX, (X86RegisterType)yReg, true); + + yReg = GetLiveRegister(yIsTemp ? 0xfffd : Op_Y); + + if (CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) { - ClearLiveRegister(0xffff, true); - RefChip16Emitter->MOV16ItoR(EAX, GPRStatus.GPRConstVal[Op_X]); - SetLiveRegister(Op_X); + dReg = GetLiveRegister(Op_X, true); + RefChip16Emitter->MOV16ItoR((X86RegisterType)dReg, GPRStatus.GPRConstVal[Op_X]); } - else CheckLiveRegister(Op_X, false); + else dReg = GetLiveRegister(Op_X); + + MoveLiveRegister(EAX, (X86RegisterType)dReg, true); - RefChip16Emitter->SHR16CLtoR(EAX); + dReg = GetLiveRegister(Op_X); - SetLiveRegister(Op_X); + RefChip16Emitter->SHR16CLtoR((X86RegisterType)dReg); + //RefChip16Emitter->MOV16RtoM((unsigned int)®_X, EAX); GPRStatus.GPRIsConst[Op_X] = false; } break; @@ -2449,38 +3229,58 @@ void RecCPU::recCpuShift() else { CPU_LOG("SHFT3 X %d, Y %d X = %x Y = %x\n", GPRStatus.GPRIsConst[Op_X], GPRStatus.GPRIsConst[Op_Y], GPRStatus.GPRConstVal[Op_X], GPRStatus.GPRConstVal[Op_Y]); - if(CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) + if (CONST_PROP && GPRStatus.GPRIsConst[Op_Y] == true) { - RefChip16Emitter->MOV16ItoR(ECX, GPRStatus.GPRConstVal[Op_Y]); + yReg = GetLiveRegister(0xfffd, true); + yIsTemp = true; + RefChip16Emitter->MOV16ItoR((X86RegisterType)yReg, GPRStatus.GPRConstVal[Op_Y]); } - else MoveLiveRegister(Op_Y, ECX); + else yReg = GetLiveRegister(Op_Y); - if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) + MoveLiveRegister(ECX, (X86RegisterType)yReg, true); + + yReg = GetLiveRegister(yIsTemp ? 0xfffd : Op_Y); + + if (CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) { - ClearLiveRegister(0xffff, true); - RefChip16Emitter->MOV16ItoR(EAX, GPRStatus.GPRConstVal[Op_X]); - SetLiveRegister(Op_X); + dReg = GetLiveRegister(Op_X, true); + RefChip16Emitter->MOV16ItoR((X86RegisterType)dReg, GPRStatus.GPRConstVal[Op_X]); } - else CheckLiveRegister(Op_X, false); + else dReg = GetLiveRegister(Op_X); + + MoveLiveRegister(EAX, (X86RegisterType)dReg, true); - RefChip16Emitter->SAR16CLtoR(EAX); + dReg = GetLiveRegister(Op_X); - SetLiveRegister(Op_X); + RefChip16Emitter->SAR16CLtoR((X86RegisterType)dReg); + //RefChip16Emitter->MOV16RtoM((unsigned int)®_X, EAX); GPRStatus.GPRIsConst[Op_X] = false; } break; default: - ClearLiveRegister(0xffff, true); + FlushLiveRegisters(true); FlushConstRegisters(true); RefChip16Emitter->MOV32ItoM((unsigned int)&OpCode, recOpCode); + RefChip16Emitter->MOV32ItoM((unsigned int)&PC, PC); RefChip16Emitter->CALL(CpuShift); return; break; } - recTestLogic(); + recTestLogic((X86RegisterType)dReg); + + if (xTemp >= 0) + FlushLiveRegister(0xfffe, false); + + if (yIsTemp == true) + { + FlushLiveRegister(GPRStatus.LiveGPRReg[yReg].gprreg, false); + } + + GPRStatus.LiveGPRReg[dReg].isdirty = true; } void RecCPU::recCpuPushPop() { + int xReg = -1; //CPU_LOG("PUSHPOP Recompiling %x from PC %x\n", recOpCode, PC-4); switch((recOpCode >> 16) & 0xf) @@ -2490,13 +3290,14 @@ void RecCPU::recCpuPushPop() if(CONST_PROP && GPRStatus.GPRIsConst[Op_X] == true) { - ClearLiveRegister(0xffff, true); + FlushLiveRegisters(true); RefChip16Emitter->MOV16ItoR(EDX, GPRStatus.GPRConstVal[Op_X]); } else { - MoveLiveRegister(Op_X, EDX); - ClearLiveRegister(0xffff, true); + xReg = GetLiveRegister(Op_X); + MoveLiveRegister(EDX, (X86RegisterType)xReg, true); + FlushLiveRegisters(true); } RefChip16Emitter->MOV32MtoR(ECX, (unsigned int)&StackPTR); RefChip16Emitter->CALL16((int)recWriteMem); @@ -2505,17 +3306,16 @@ void RecCPU::recCpuPushPop() break; //Decrease Stack Pointer and load value in to Reg X case 0x1: - ClearLiveRegister(0xffff, (Op_X == GPRStatus.LiveGPRReg) ? false : true); + FlushLiveRegisters(true); RefChip16Emitter->SUB32ItoM((unsigned int)&StackPTR, 2); RefChip16Emitter->MOV16MtoR(ECX, (unsigned int)&StackPTR); RefChip16Emitter->CALL16((int)recReadMem); - RefChip16Emitter->MOV16RtoM((unsigned int)®_X, EAX); + AssignLiveRegister(Op_X, EAX); GPRStatus.GPRIsConst[Op_X] = false; - SetLiveRegister(Op_X); break; //Store all GPR registers in the stack, increase SP by 32 (16 x 2) case 0x2: - ClearLiveRegister(0xffff, true); + FlushLiveRegisters(true); for(int i = 0; i < 16; i++) { if(CONST_PROP && GPRStatus.GPRIsConst[i] == true) RefChip16Emitter->MOV16ItoR(EDX, GPRStatus.GPRConstVal[i]); @@ -2528,7 +3328,7 @@ void RecCPU::recCpuPushPop() //Decrease SP by 32 and POP all GPR registers case 0x3: //CPU_LOG("Restore All Registers on stack PC = %x\n", PC); - ClearLiveRegister(0xffff, false); + FlushLiveRegisters(false); FlushConstRegisters(false); for(int i = 15; i >= 0; i--) @@ -2538,11 +3338,11 @@ void RecCPU::recCpuPushPop() RefChip16Emitter->CALL16((int)recReadMem); RefChip16Emitter->MOV16RtoM((unsigned int)&GPR[i], EAX); } - SetLiveRegister(0); + AssignLiveRegister(0, EAX); break; //Store flags register on stack, increase SP by 2 case 0x4: - ClearLiveRegister(0xffff, true); + FlushLiveRegisters(true); RefChip16Emitter->MOV16MtoR(EDX, (unsigned int)&Flag._u16); RefChip16Emitter->MOV32MtoR(ECX, (unsigned int)&StackPTR); RefChip16Emitter->CALL16((int)recWriteMem); @@ -2550,7 +3350,7 @@ void RecCPU::recCpuPushPop() break; //Decrease SP by 2, restore flags register case 0x5: - ClearLiveRegister(0xffff, true); + FlushLiveRegisters(true); RefChip16Emitter->SUB32ItoM((unsigned int)&StackPTR, 2); RefChip16Emitter->MOV16MtoR(ECX, (unsigned int)&StackPTR); RefChip16Emitter->CALL16((int)recReadMem); @@ -2558,13 +3358,15 @@ void RecCPU::recCpuPushPop() break; default: - ClearLiveRegister(0xffff, true); + FlushLiveRegisters(true); FlushConstRegisters(true); RefChip16Emitter->MOV32ItoM((unsigned int)&OpCode, recOpCode); + RefChip16Emitter->MOV32ItoM((unsigned int)&PC, PC); RefChip16Emitter->CALL(CpuPushPop); + return; break; + } - } void RecCPU::recCpuPallate() @@ -2574,16 +3376,24 @@ void RecCPU::recCpuPallate() case 0x0: case 0x1: default: - ClearLiveRegister(0xffff, true); + FlushLiveRegisters(true); FlushConstRegisters(true); RefChip16Emitter->MOV32ItoM((unsigned int)&OpCode, recOpCode); + RefChip16Emitter->MOV32ItoM((unsigned int)&PC, PC); RefChip16Emitter->CALL(CpuPallate); + return; break; } } void RecCPU::recCpuNOTNEG() { + int xReg = -1; + int yReg = -1; + int xTemp = -1; + int dReg = -1; + bool yIsTemp = false; + RefChip16Emitter->AND16ItoM((unsigned int)&Flag._u16, ~0x84); switch((recOpCode >> 16) & 0xf) { @@ -2599,14 +3409,13 @@ void RecCPU::recCpuNOTNEG() else if(GPRStatus.GPRConstVal[Op_X] & 0x8000) flags |= 0x80; RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, flags); + return; } else { - FlushLiveRegister(); + dReg = GetLiveRegister(Op_X, true); - RefChip16Emitter->MOV16ItoR(EAX, ~IMMEDIATE); - SetLiveRegister(Op_X); - recTestLogic(); + RefChip16Emitter->MOV16ItoR((X86RegisterType)dReg, ~IMMEDIATE); } break; case 0x1: @@ -2620,14 +3429,12 @@ void RecCPU::recCpuNOTNEG() else if(GPRStatus.GPRConstVal[Op_X] & 0x8000) flags |= 0x80; RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, flags); + return; } else { - CheckLiveRegister(Op_X, false); - - RefChip16Emitter->NOT16R(EAX); - SetLiveRegister(Op_X); - recTestLogic(); + dReg = GetLiveRegister(Op_X); + RefChip16Emitter->NOT16R((X86RegisterType)dReg); } break; case 0x2: @@ -2638,21 +3445,25 @@ void RecCPU::recCpuNOTNEG() GPRStatus.GPRConstVal[Op_X] = ~GPRStatus.GPRConstVal[Op_Y]; GPRStatus.GPRIsConst[Op_X] = true; - ClearLiveRegister(Op_X, false); + FlushLiveRegister(Op_X, false); if(GPRStatus.GPRConstVal[Op_X] == 0) flags |= 0x4; else if(GPRStatus.GPRConstVal[Op_X] & 0x8000) flags |= 0x80; RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, flags); + return; } else { - CheckLiveRegister(Op_Y, true); - - RefChip16Emitter->NOT16R(EAX); - SetLiveRegister(Op_X); + dReg = GetLiveRegister(Op_Y); + if (Op_X != Op_Y) + { + FlushLiveRegister(dReg, true); + AssignLiveRegister((X86RegisterType)dReg, Op_X); + } + RefChip16Emitter->NOT16R((X86RegisterType)dReg); + GPRStatus.GPRIsConst[Op_X] = false; - recTestLogic(); } break; case 0x3: @@ -2662,20 +3473,18 @@ void RecCPU::recCpuNOTNEG() GPRStatus.GPRConstVal[Op_X] = -IMMEDIATE; GPRStatus.GPRIsConst[Op_X] = true; - ClearLiveRegister(Op_X, false); + FlushLiveRegister(Op_X, false); if(GPRStatus.GPRConstVal[Op_X] == 0) flags |= 0x4; else if(GPRStatus.GPRConstVal[Op_X] & 0x8000) flags |= 0x80; RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, flags); + return; } else { - FlushLiveRegister(); - - RefChip16Emitter->MOV16ItoR(EAX, -IMMEDIATE); - SetLiveRegister(Op_X); - recTestLogic(); + dReg = GetLiveRegister(Op_X); + RefChip16Emitter->MOV16ItoR((X86RegisterType)dReg, -IMMEDIATE); } break; case 0x4: @@ -2689,15 +3498,12 @@ void RecCPU::recCpuNOTNEG() else if(GPRStatus.GPRConstVal[Op_X] & 0x8000) flags |= 0x80; RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, flags); + return; } else { - FlushConstRegisters(true); - CheckLiveRegister(Op_X, false); - - RefChip16Emitter->NEG16R(EAX); - SetLiveRegister(Op_X); - recTestLogic(); + dReg = GetLiveRegister(Op_X); + RefChip16Emitter->NEG16R((X86RegisterType)dReg); } break; case 0x5: @@ -2710,23 +3516,40 @@ void RecCPU::recCpuNOTNEG() if(GPRStatus.GPRConstVal[Op_X] == 0) flags |= 0x4; else if(GPRStatus.GPRConstVal[Op_X] & 0x8000) flags |= 0x80; - ClearLiveRegister(Op_X, false); + FlushLiveRegister(Op_X, false); RefChip16Emitter->OR16ItoM((unsigned int)&Flag._u16, flags); + return; } else { - CheckLiveRegister(Op_Y, true); - RefChip16Emitter->NEG16R(EAX); - SetLiveRegister(Op_X); - recTestLogic(); + yReg = GetLiveRegister(Op_Y); + dReg = GetLiveRegister(Op_X); + + if (Op_X != Op_Y) + RefChip16Emitter->MOV16RtoR((X86RegisterType)dReg, (X86RegisterType)yReg); + + RefChip16Emitter->NEG16R((X86RegisterType)dReg); + GPRStatus.GPRIsConst[Op_X] = false; } break; default: - ClearLiveRegister(0xffff, true); + FlushLiveRegisters(true); FlushConstRegisters(true); RefChip16Emitter->MOV32ItoM((unsigned int)&OpCode, recOpCode); + RefChip16Emitter->MOV32ItoM((unsigned int)&PC, PC); RefChip16Emitter->CALL(CpuNOTNEG); + return; break; } + recTestLogic((X86RegisterType)dReg); + if (yIsTemp == true) + { + FlushLiveRegister(GPRStatus.LiveGPRReg[yReg].gprreg, false); + } + if (xTemp >= 0) + FlushLiveRegister(0xfffe, false); + + ToggleLockRegister(EDX, false); + GPRStatus.LiveGPRReg[dReg].isdirty = true; } \ No newline at end of file diff --git a/RefChip16/RecCPU.h b/RefChip16/RecCPU.h index cdaf693..61e76ad 100644 --- a/RefChip16/RecCPU.h +++ b/RefChip16/RecCPU.h @@ -34,11 +34,17 @@ class RecCPU unsigned char* RecompileBlock(); //Function which handles generation of the recompiled code unsigned char* __fastcall ExecuteBlock(); //This function returns the codebuffer pointer for start of rec code. void FlushConstRegisters(bool flush); - void CheckLiveRegister(unsigned char GPRReg, bool writeback); - void FlushLiveRegister(); - void ClearLiveRegister(unsigned short GPRReg, bool flush); - void SetLiveRegister(unsigned char GPRReg); - void MoveLiveRegister(unsigned short GPRReg, X86RegisterType to); + void IncRegisterAge(); + void FlushLiveRegisters(bool flush); + void ToggleLockRegister(int reg, bool locked); + void MoveLiveRegister(X86RegisterType toreg, X86RegisterType fromreg, bool swap); + void SetupMulDivSrcRegister(unsigned short srcReg, unsigned short tarReg, bool isSigned); + int GetLiveRegister(unsigned short GPRReg, bool isDestOnly); + int GetLiveRegisterNoAssign(unsigned short GPRReg); + int GetFreeLiveRegister(unsigned short GPRReg, bool isDestOnly); + void AssignLiveRegister(unsigned char GPRReg, int x86Reg); + void FlushLiveRegister(unsigned short GPRReg, bool flush); + void ReAssignLiveRegister(int x86RegFrom, int x86RegTo); void ResetRecMem(); void recCpuCore(); @@ -47,11 +53,11 @@ class RecCPU void recCpuStore(); void recCpuAdd(); void recADDCheckCarry(); - void recADDCheckOVF(); + void recADDCheckOVF(X86RegisterType yReg, X86RegisterType dReg, X86RegisterType xTemp, bool XisY); void recSUBCheckCarry(); - void recSUBCheckOVF(); + void recSUBCheckOVF(X86RegisterType yReg, X86RegisterType dReg, X86RegisterType xTemp, bool XisY); void recCpuSub(); - void recTestLogic(); + void recTestLogic(X86RegisterType dReg); void recCpuAND(); void recCpuOR(); void recCpuXOR(); diff --git a/RefChip16/RefChip16.vcxproj b/RefChip16/RefChip16.vcxproj index 7d8bdb7..319a3a8 100644 --- a/RefChip16/RefChip16.vcxproj +++ b/RefChip16/RefChip16.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -24,7 +24,7 @@ Application true NotSet - v110 + v140 Application @@ -32,13 +32,14 @@ true NotSet false - v110 + v140 Dynamic false + v140 @@ -98,7 +99,7 @@ Speed - StreamingSIMDExtensions2 + NoExtensions MultiThreaded true true diff --git a/RefChip16/main.cpp b/RefChip16/main.cpp index 44feaf3..ccd85a9 100644 --- a/RefChip16/main.cpp +++ b/RefChip16/main.cpp @@ -57,8 +57,8 @@ int prev_v_cycle = 0; unsigned int v_cycle = prev_v_cycle; time_t counter; -int SCREEN_WIDTH = 320; -int SCREEN_HEIGHT = 240; +unsigned short SCREEN_WIDTH = 320; +unsigned short SCREEN_HEIGHT = 240; RECT rc; using namespace CPU; @@ -76,7 +76,8 @@ void CleanupRoutine() int SaveIni(){ - //fopen_s(&iniFile, "./refchip16.ini","w+"); //Open the file, args r = read, b = binary + fopen_s(&iniFile, "./refchip16.ini", "w+b"); //Open the file, args r = read, b = binary + if (iniFile!=NULL) //If the file exists { @@ -88,9 +89,9 @@ int SaveIni(){ rewind (iniFile); - CPU_LOG("Saving Ini %x and %x and %x pos %d\n", Recompiler, MenuVSync, MenuScale, ftell(iniFile)); + ///CPU_LOG("Saving Ini %x and %x and %x pos %d\n", Recompiler, MenuVSync, MenuScale, ftell(iniFile)); fwrite(&inisettings,1,5,iniFile); //Read in the file - CPU_LOG("pos %d\n", Recompiler, MenuVSync, MenuScale, ftell(iniFile)); + //CPU_LOG("Rec %d, Vsync %d, Scale %d, pos %d\n", Recompiler, MenuVSync, MenuScale, ftell(iniFile)); fclose(iniFile); //Close the file if(LoggingEnable) @@ -157,13 +158,13 @@ int LoadIni(){ CPU_LOG("Loading Ini %x and %x and %x\n", Recompiler, MenuVSync, MenuScale); fclose(iniFile); //Close the file - fopen_s(&iniFile, "./refchip16.ini","wb+"); //Open the file, args r+ = read, b = binary + //fopen_s(&iniFile, "./refchip16.ini","wb+"); //Open the file, args r+ = read, b = binary return 0; } else { CPU_LOG("Error Loading Ini\n"); - fopen_s(&iniFile, "./refchip16.ini","wb+"); //Open the file, args r+ = read, b = binary + fopen_s(&iniFile, "./refchip16.ini","r+b"); //Open the file, args r+ = read, b = binary //User cancelled, either way, do nothing. return 1; } @@ -171,7 +172,7 @@ int LoadIni(){ void UpdateTitleBar(HWND hWnd) { - sprintf_s(headingstr, "RefChip16 V1.61 FPS: %d Recompiler %s", fps2, Recompiler ? "Enabled" : "Disabled"); + sprintf_s(headingstr, "RefChip16 V1.7 FPS: %d Recompiler %s", fps2, Recompiler ? "Enabled" : "Disabled"); SetWindowText(hWnd, headingstr); } // The entry point for any Windows program @@ -593,9 +594,10 @@ LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPara ToggleLogging(hWnd); break; case ID_ABOUT: - MessageBox(hWnd, "RefChip16 V1.61 Written by Refraction - Big thanks to the Chip16 devs for this :)", "RefChip16", 0); + MessageBox(hWnd, "RefChip16 V1.7 Written by Refraction - Big thanks to the Chip16 devs for this :)", "RefChip16", 0); break; case ID_EXIT: + SaveIni(); DestroyWindow(hWnd); return 0; break; diff --git a/Release/RefChip16.exe b/Release/RefChip16.exe index 284abf0..b109a42 100644 Binary files a/Release/RefChip16.exe and b/Release/RefChip16.exe differ