OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /or1k/tags/stable_0_2_0_rc1/or1ksim/cpu/or32
    from Rev 1572 to Rev 1765
    Reverse comparison

Rev 1572 → Rev 1765

/or32.c
0,0 → 1,1320
/* Table of opcodes for the OpenRISC 1000 ISA.
Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
Contributed by Damjan Lampret (lampret@opencores.org).
This file is part of gen_or1k_isa, or1ksim, GDB and GAS.
 
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
 
/*
* $Log: not supported by cvs2svn $
* Revision 1.46 2005/08/18 22:13:27 phoenix
* fixed l.maci encoding
*
* Revision 1.45 2005/04/27 19:13:13 nogj
* l.rfe does not have a delay slot. Don't mark it as such.
*
* Revision 1.44 2005/03/31 16:09:57 nogj
* Implement a dynamic recompiler to speed up the execution
*
* Revision 1.43 2005/03/31 16:01:59 nogj
* Reclasify l.trap and l.sys to be an exception instruction
*
* Revision 1.42 2005/03/16 12:25:56 nogj
* Fix the parameters to the l.ff1/l.maci instructions
*
* Revision 1.41 2005/02/09 17:41:03 nogj
* Mark a simulated cpu address as such, by introducing the new oraddr_t type
*
* Revision 1.40 2005/01/27 14:14:13 nogj
* Remove the global op structure
*
* Revision 1.39 2005/01/27 13:35:40 nogj
* * Fix generate.c to produce a execgen.c with less warnings.
* * Fix the --enable-simple configure option.
*
* Revision 1.38 2005/01/27 13:15:50 nogj
* Mark wich operand is the destination operand in the architechture definition
*
* Revision 1.37 2005/01/11 15:41:58 andreje
* l.ff1 instruction added
*
* Revision 1.36 2004/07/22 20:17:23 phoenix
* removed includes
*
* Revision 1.35 2004/07/19 23:07:37 phoenix
* Gyorgy Jeney: extensive cleanup
*
* Revision 1.34 2004/06/27 22:56:48 lampret
* Updated instruction set descriptions. Changed FP instructions encoding.
*
* Revision 1.33 2004/05/09 19:52:31 lampret
* Changed desciption of the l.cust5 insns
*
* Revision 1.31 2003/07/01 19:34:49 csanchez
* Added support for l.addc instruction.
*
* Revision 1.30 2003/01/28 03:49:24 lampret
* Added cvs log keywords
*
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
 
 
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAS_EXECUTION
# ifdef HAVE_INTTYPES_H
# include <inttypes.h> /* ...but to get arch.h we need uint{8,16,32}_t... */
# endif
# include "port.h"
# include "arch.h" /* ...but to get abstract.h, we need oraddr_t... */
# include "abstract.h" /* To get struct iqueue_entry... */
# include "debug.h" /* To get debug() */
#endif
#include "opcode/or32.h"
 
/* **INDENT-OFF** */
 
/* We treat all letters the same in encode/decode routines so
we need to assign some characteristics to them like signess etc.*/
CONST struct or32_letter or32_letters[] =
{
{ 'A', NUM_UNSIGNED },
{ 'B', NUM_UNSIGNED },
{ 'D', NUM_UNSIGNED },
{ 'I', NUM_SIGNED },
{ 'K', NUM_UNSIGNED },
{ 'L', NUM_UNSIGNED },
{ 'N', NUM_SIGNED },
{ '0', NUM_UNSIGNED },
{ '\0', 0 } /* dummy entry */
};
 
/* Opcode encoding:
machine[31:30]: first two bits of opcode
00 - neither of source operands is GPR
01 - second source operand is GPR (rB)
10 - first source operand is GPR (rA)
11 - both source operands are GPRs (rA and rB)
machine[29:26]: next four bits of opcode
machine[25:00]: instruction operands (specific to individual instruction)
 
Recommendation: irrelevant instruction bits should be set with a value of
bits in same positions of instruction preceding current instruction in the
code (when assembling).
*/
 
#ifdef HAS_EXECUTION
# if SIMPLE_EXECUTION
# define EFN &l_none
# define EF(func) &(func)
# define EFI &l_invalid
# elif COMPLEX_EXECUTION
# define EFN "l_none"
# define EFI "l_invalid"
# ifdef __GNUC__
# define EF(func) #func
# else
# define EF(func) "func"
# endif
# else /* DYNAMIC_EXECUTION */
# define EFN &l_none
# define EF(func) &(gen_ ##func)
# define EFI &gen_l_invalid
# endif
#else /* HAS_EXECUTION */
# define EFN &l_none
# define EF(func) EFN
# define EFI EFN
#endif /* HAS_EXECUTION */
 
CONST struct or32_opcode or32_opcodes[] =
{
 
{ "l.j", "N", "00 0x0 NNNNN NNNNN NNNN NNNN NNNN NNNN",
EF(l_j), OR32_IF_DELAY, it_jump },
{ "l.jal", "N", "00 0x1 NNNNN NNNNN NNNN NNNN NNNN NNNN",
EF(l_jal), OR32_IF_DELAY, it_jump },
{ "l.bnf", "N", "00 0x3 NNNNN NNNNN NNNN NNNN NNNN NNNN",
EF(l_bnf), OR32_IF_DELAY | OR32_R_FLAG, it_branch },
{ "l.bf", "N", "00 0x4 NNNNN NNNNN NNNN NNNN NNNN NNNN",
EF(l_bf), OR32_IF_DELAY | OR32_R_FLAG, it_branch },
{ "l.nop", "K", "00 0x5 01--- ----- KKKK KKKK KKKK KKKK",
EF(l_nop), 0, it_nop },
{ "l.movhi", "rD,K", "00 0x6 DDDDD ----0 KKKK KKKK KKKK KKKK",
EF(l_movhi), 0, it_movimm },
{ "l.macrc", "rD", "00 0x6 DDDDD ----1 0000 0000 0000 0000",
EF(l_macrc), 0, it_mac },
{ "l.sys", "K", "00 0x8 00000 00000 KKKK KKKK KKKK KKKK",
EF(l_sys), 0, it_exception },
{ "l.trap", "K", "00 0x8 01000 00000 KKKK KKKK KKKK KKKK",
EF(l_trap), 0, it_exception },
{ "l.msync", "", "00 0x8 10000 00000 0000 0000 0000 0000", EFN,
0, it_unknown },
{ "l.psync", "", "00 0x8 10100 00000 0000 0000 0000 0000", EFN,
0, it_unknown },
{ "l.csync", "", "00 0x8 11000 00000 0000 0000 0000 0000", EFN,
0, it_unknown },
{ "l.rfe", "", "00 0x9 ----- ----- ---- ---- ---- ----",
EF(l_rfe), 0, it_exception },
{ "lv.all_eq.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x0", EFI, 0,
it_unknown },
{ "lv.all_eq.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x1", EFI, 0,
it_unknown },
{ "lv.all_ge.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x2", EFI, 0,
it_unknown },
{ "lv.all_ge.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x3", EFI, 0,
it_unknown },
{ "lv.all_gt.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x4", EFI, 0,
it_unknown },
{ "lv.all_gt.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x5", EFI, 0,
it_unknown },
{ "lv.all_le.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x6", EFI, 0,
it_unknown },
{ "lv.all_le.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x7", EFI, 0,
it_unknown },
{ "lv.all_lt.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x8", EFI, 0,
it_unknown },
{ "lv.all_lt.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x9", EFI, 0,
it_unknown },
{ "lv.all_ne.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0xA", EFI, 0,
it_unknown },
{ "lv.all_ne.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0xB", EFI, 0,
it_unknown },
{ "lv.any_eq.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x0", EFI, 0,
it_unknown },
{ "lv.any_eq.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x1", EFI, 0,
it_unknown },
{ "lv.any_ge.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x2", EFI, 0,
it_unknown },
{ "lv.any_ge.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x3", EFI, 0,
it_unknown },
{ "lv.any_gt.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x4", EFI, 0,
it_unknown },
{ "lv.any_gt.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x5", EFI, 0,
it_unknown },
{ "lv.any_le.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x6", EFI, 0,
it_unknown },
{ "lv.any_le.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x7", EFI, 0,
it_unknown },
{ "lv.any_lt.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x8", EFI, 0,
it_unknown },
{ "lv.any_lt.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x9", EFI, 0,
it_unknown },
{ "lv.any_ne.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0xA", EFI, 0,
it_unknown },
{ "lv.any_ne.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0xB", EFI, 0,
it_unknown },
{ "lv.add.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x0", EFI, 0,
it_unknown },
{ "lv.add.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x1", EFI, 0,
it_unknown },
{ "lv.adds.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x2", EFI, 0,
it_unknown },
{ "lv.adds.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x3", EFI, 0,
it_unknown },
{ "lv.addu.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x4", EFI, 0,
it_unknown },
{ "lv.addu.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x5", EFI, 0,
it_unknown },
{ "lv.addus.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x6", EFI, 0,
it_unknown },
{ "lv.addus.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x7", EFI, 0,
it_unknown },
{ "lv.and", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x8", EFI, 0,
it_unknown },
{ "lv.avg.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x9", EFI, 0,
it_unknown },
{ "lv.avg.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0xA", EFI, 0,
it_unknown },
{ "lv.cmp_eq.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x0", EFI, 0,
it_unknown },
{ "lv.cmp_eq.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x1", EFI, 0,
it_unknown },
{ "lv.cmp_ge.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x2", EFI, 0,
it_unknown },
{ "lv.cmp_ge.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x3", EFI, 0,
it_unknown },
{ "lv.cmp_gt.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x4", EFI, 0,
it_unknown },
{ "lv.cmp_gt.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x5", EFI, 0,
it_unknown },
{ "lv.cmp_le.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x6", EFI, 0,
it_unknown },
{ "lv.cmp_le.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x7", EFI, 0,
it_unknown },
{ "lv.cmp_lt.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x8", EFI, 0,
it_unknown },
{ "lv.cmp_lt.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x9", EFI, 0,
it_unknown },
{ "lv.cmp_ne.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0xA", EFI, 0,
it_unknown },
{ "lv.cmp_ne.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0xB", EFI, 0,
it_unknown },
{ "lv.madds.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0x4", EFI, 0,
it_unknown },
{ "lv.max.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0x5", EFI, 0,
it_unknown },
{ "lv.max.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0x6", EFI, 0,
it_unknown },
{ "lv.merge.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0x7", EFI, 0,
it_unknown },
{ "lv.merge.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0x8", EFI, 0,
it_unknown },
{ "lv.min.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0x9", EFI, 0,
it_unknown },
{ "lv.min.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0xA", EFI, 0,
it_unknown },
{ "lv.msubs.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0xB", EFI, 0,
it_unknown },
{ "lv.muls.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0xC", EFI, 0,
it_unknown },
{ "lv.nand", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0xD", EFI, 0,
it_unknown },
{ "lv.nor", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0xE", EFI, 0,
it_unknown },
{ "lv.or", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0xF", EFI, 0,
it_unknown },
{ "lv.pack.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x0", EFI, 0,
it_unknown },
{ "lv.pack.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x1", EFI, 0,
it_unknown },
{ "lv.packs.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x2", EFI, 0,
it_unknown },
{ "lv.packs.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x3", EFI, 0,
it_unknown },
{ "lv.packus.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x4", EFI, 0,
it_unknown },
{ "lv.packus.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x5", EFI, 0,
it_unknown },
{ "lv.perm.n", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x6", EFI, 0,
it_unknown },
{ "lv.rl.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x7", EFI, 0,
it_unknown },
{ "lv.rl.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x8", EFI, 0,
it_unknown },
{ "lv.sll.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x9", EFI, 0,
it_unknown },
{ "lv.sll.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0xA", EFI, 0,
it_unknown },
{ "lv.sll", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0xB", EFI, 0,
it_unknown },
{ "lv.srl.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0xC", EFI, 0,
it_unknown },
{ "lv.srl.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0xD", EFI, 0,
it_unknown },
{ "lv.sra.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0xE", EFI, 0,
it_unknown },
{ "lv.sra.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0xF", EFI, 0,
it_unknown },
{ "lv.srl", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x0", EFI, 0,
it_unknown },
{ "lv.sub.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x1", EFI, 0,
it_unknown },
{ "lv.sub.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x2", EFI, 0,
it_unknown },
{ "lv.subs.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x3", EFI, 0,
it_unknown },
{ "lv.subs.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x4", EFI, 0,
it_unknown },
{ "lv.subu.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x5", EFI, 0,
it_unknown },
{ "lv.subu.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x6", EFI, 0,
it_unknown },
{ "lv.subus.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x7", EFI, 0,
it_unknown },
{ "lv.subus.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x8", EFI, 0,
it_unknown },
{ "lv.unpack.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x9", EFI, 0,
it_unknown },
{ "lv.unpack.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0xA", EFI, 0,
it_unknown },
{ "lv.xor", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0xB", EFI, 0,
it_unknown },
{ "lv.cust1", "", "00 0xA ----- ----- ---- ---- 0xC ----", EFI, 0,
it_unknown },
{ "lv.cust2", "", "00 0xA ----- ----- ---- ---- 0xD ----", EFI, 0,
it_unknown },
{ "lv.cust3", "", "00 0xA ----- ----- ---- ---- 0xE ----", EFI, 0,
it_unknown },
{ "lv.cust4", "", "00 0xA ----- ----- ---- ---- 0xF ----", EFI, 0,
it_unknown },
 
{ "l.jr", "rB", "01 0x1 ----- ----- BBBB B--- ---- ----",
EF(l_jr), OR32_IF_DELAY, it_jump },
{ "l.jalr", "rB", "01 0x2 ----- ----- BBBB B--- ---- ----",
EF(l_jalr), OR32_IF_DELAY, it_jump },
{ "l.maci", "rA,I", "01 0x3 IIIII AAAAA ---- -III IIII IIII",
EF(l_mac), 0, it_mac },
{ "l.cust1", "", "01 0xC ----- ----- ---- ---- ---- ----",
EF(l_cust1), 0, it_unknown },
{ "l.cust2", "", "01 0xD ----- ----- ---- ---- ---- ----",
EF(l_cust2), 0, it_unknown },
{ "l.cust3", "", "01 0xE ----- ----- ---- ---- ---- ----",
EF(l_cust3), 0, it_unknown },
{ "l.cust4", "", "01 0xF ----- ----- ---- ---- ---- ----",
EF(l_cust4), 0, it_unknown },
 
{ "l.ld", "rD,I(rA)", "10 0x0 DDDDD AAAAA IIII IIII IIII IIII", EFI,
0, it_load },
{ "l.lwz", "rD,I(rA)", "10 0x1 DDDDD AAAAA IIII IIII IIII IIII",
EF(l_lwz), 0, it_load },
{ "l.lws", "rD,I(rA)", "10 0x2 DDDDD AAAAA IIII IIII IIII IIII", EFI,
0, it_load },
{ "l.lbz", "rD,I(rA)", "10 0x3 DDDDD AAAAA IIII IIII IIII IIII",
EF(l_lbz), 0, it_load },
{ "l.lbs", "rD,I(rA)", "10 0x4 DDDDD AAAAA IIII IIII IIII IIII",
EF(l_lbs), 0, it_load },
{ "l.lhz", "rD,I(rA)", "10 0x5 DDDDD AAAAA IIII IIII IIII IIII",
EF(l_lhz), 0, it_load },
{ "l.lhs", "rD,I(rA)", "10 0x6 DDDDD AAAAA IIII IIII IIII IIII",
EF(l_lhs), 0, it_load },
 
{ "l.addi", "rD,rA,I", "10 0x7 DDDDD AAAAA IIII IIII IIII IIII",
EF(l_add), OR32_W_FLAG, it_arith },
{ "l.addic", "rD,rA,I", "10 0x8 DDDDD AAAAA IIII IIII IIII IIII", EFI,
0, it_arith },
{ "l.andi", "rD,rA,K", "10 0x9 DDDDD AAAAA KKKK KKKK KKKK KKKK",
EF(l_and), OR32_W_FLAG, it_arith },
{ "l.ori", "rD,rA,K", "10 0xA DDDDD AAAAA KKKK KKKK KKKK KKKK",
EF(l_or), 0, it_arith },
{ "l.xori", "rD,rA,I", "10 0xB DDDDD AAAAA IIII IIII IIII IIII",
EF(l_xor), 0, it_arith },
{ "l.muli", "rD,rA,I", "10 0xC DDDDD AAAAA IIII IIII IIII IIII",
EF(l_mul), 0, it_arith },
{ "l.mfspr", "rD,rA,K", "10 0xD DDDDD AAAAA KKKK KKKK KKKK KKKK",
EF(l_mfspr), 0, it_move },
{ "l.slli", "rD,rA,L", "10 0xE DDDDD AAAAA ---- ---- 00LL LLLL",
EF(l_sll), 0, it_shift },
{ "l.srli", "rD,rA,L", "10 0xE DDDDD AAAAA ---- ---- 01LL LLLL",
EF(l_srl), 0, it_shift },
{ "l.srai", "rD,rA,L", "10 0xE DDDDD AAAAA ---- ---- 10LL LLLL",
EF(l_sra), 0, it_shift },
{ "l.rori", "rD,rA,L", "10 0xE DDDDD AAAAA ---- ---- 11LL LLLL", EFI,
0, it_shift },
 
{ "l.sfeqi", "rA,I", "10 0xF 00000 AAAAA IIII IIII IIII IIII",
EF(l_sfeq), OR32_W_FLAG, it_compare },
{ "l.sfnei", "rA,I", "10 0xF 00001 AAAAA IIII IIII IIII IIII",
EF(l_sfne), OR32_W_FLAG, it_compare },
{ "l.sfgtui", "rA,I", "10 0xF 00010 AAAAA IIII IIII IIII IIII",
EF(l_sfgtu), OR32_W_FLAG, it_compare },
{ "l.sfgeui", "rA,I", "10 0xF 00011 AAAAA IIII IIII IIII IIII",
EF(l_sfgeu), OR32_W_FLAG, it_compare },
{ "l.sfltui", "rA,I", "10 0xF 00100 AAAAA IIII IIII IIII IIII",
EF(l_sfltu), OR32_W_FLAG, it_compare },
{ "l.sfleui", "rA,I", "10 0xF 00101 AAAAA IIII IIII IIII IIII",
EF(l_sfleu), OR32_W_FLAG, it_compare },
{ "l.sfgtsi", "rA,I", "10 0xF 01010 AAAAA IIII IIII IIII IIII",
EF(l_sfgts), OR32_W_FLAG, it_compare },
{ "l.sfgesi", "rA,I", "10 0xF 01011 AAAAA IIII IIII IIII IIII",
EF(l_sfges), OR32_W_FLAG, it_compare },
{ "l.sfltsi", "rA,I", "10 0xF 01100 AAAAA IIII IIII IIII IIII",
EF(l_sflts), OR32_W_FLAG, it_compare },
{ "l.sflesi", "rA,I", "10 0xF 01101 AAAAA IIII IIII IIII IIII",
EF(l_sfles), OR32_W_FLAG, it_compare },
 
{ "l.mtspr", "rA,rB,K", "11 0x0 KKKKK AAAAA BBBB BKKK KKKK KKKK",
EF(l_mtspr), 0, it_move },
{ "l.mac", "rA,rB", "11 0x1 ----- AAAAA BBBB B--- ---- 0x1",
EF(l_mac), 0, it_mac },
{ "l.msb", "rA,rB", "11 0x1 ----- AAAAA BBBB B--- ---- 0x2",
EF(l_msb), 0, it_mac },
 
{ "lf.add.s", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x0 0x0",
EF(lf_add_s), 0, it_float },
{ "lf.sub.s", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x0 0x1",
EF(lf_sub_s), 0, it_float },
{ "lf.mul.s", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x0 0x2",
EF(lf_mul_s), 0, it_float },
{ "lf.div.s", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x0 0x3",
EF(lf_div_s), 0, it_float },
{ "lf.itof.s", "rD,rA", "11 0x2 DDDDD AAAAA 0000 0--- 0x0 0x4",
EF(lf_itof_s), 0, it_float },
{ "lf.ftoi.s", "rD,rA", "11 0x2 DDDDD AAAAA 0000 0--- 0x0 0x5",
EF(lf_ftoi_s), 0, it_float },
{ "lf.rem.s", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x0 0x6",
EF(lf_rem_s), 0, it_float },
{ "lf.madd.s", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x0 0x7",
EF(lf_madd_s), 0, it_float },
{ "lf.sfeq.s", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x0 0x8",
EF(lf_sfeq_s), 0, it_float },
{ "lf.sfne.s", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x0 0x9",
EF(lf_sfne_s), 0, it_float },
{ "lf.sfgt.s", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x0 0xA",
EF(lf_sfgt_s), 0, it_float },
{ "lf.sfge.s", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x0 0xB",
EF(lf_sfge_s), 0, it_float },
{ "lf.sflt.s", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x0 0xC",
EF(lf_sflt_s), 0, it_float },
{ "lf.sfle.s", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x0 0xD",
EF(lf_sfle_s), 0, it_float },
{ "lf.cust1.s", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0xD ----", EFI,
0, it_float },
 
{ "lf.add.d", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x1 0x0", EFI, 0,
it_float },
{ "lf.sub.d", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x1 0x1", EFI, 0,
it_float },
{ "lf.mul.d", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x1 0x2", EFI, 0,
it_float },
{ "lf.div.d", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x1 0x3", EFI, 0,
it_float },
{ "lf.itof.d", "rD,rA", "11 0x2 DDDDD AAAAA 0000 0--- 0x1 0x4", EFI, 0,
it_float },
{ "lf.ftoi.d", "rD,rA", "11 0x2 DDDDD AAAAA 0000 0--- 0x1 0x5", EFI, 0,
it_float },
{ "lf.rem.d", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x1 0x6", EFI, 0,
it_float },
{ "lf.madd.d", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x1 0x7", EFI, 0,
it_float },
{ "lf.sfeq.d", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x1 0x8", EFI, 0,
it_float },
{ "lf.sfne.d", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x1 0x9", EFI, 0,
it_float },
{ "lf.sfgt.d", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x1 0xA", EFI, 0,
it_float },
{ "lf.sfge.d", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x1 0xB", EFI, 0,
it_float },
{ "lf.sflt.d", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x1 0xC", EFI, 0,
it_float },
{ "lf.sfle.d", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x1 0xD", EFI, 0,
it_float },
{ "lf.cust1.d", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0xE ----", EFI, 0,
it_float },
 
{ "l.sd", "I(rD),rB", "11 0x4 IIIII DDDDD BBBB BIII IIII IIII", EFI,
0, it_store },
{ "l.sw", "I(rD),rB", "11 0x5 IIIII DDDDD BBBB BIII IIII IIII",
EF(l_sw), 0, it_store },
{ "l.sb", "I(rD),rB", "11 0x6 IIIII DDDDD BBBB BIII IIII IIII",
EF(l_sb), 0, it_store },
{ "l.sh", "I(rD),rB", "11 0x7 IIIII DDDDD BBBB BIII IIII IIII",
EF(l_sh), 0, it_store },
 
{ "l.add", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 ---- 0x0",
EF(l_add), OR32_W_FLAG, it_arith },
{ "l.addc", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 ---- 0x1",
EF(l_addc), OR32_W_FLAG, it_arith },
{ "l.sub", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 ---- 0x2",
EF(l_sub), 0, it_arith },
{ "l.and", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 ---- 0x3",
EF(l_and), OR32_W_FLAG, it_arith },
{ "l.or", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 ---- 0x4",
EF(l_or), 0, it_arith },
{ "l.xor", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 ---- 0x5",
EF(l_xor), 0, it_arith },
{ "l.mul", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-11 ---- 0x6",
EF(l_mul), 0, it_arith },
 
{ "l.sll", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 00-- 0x8",
EF(l_sll), 0, it_shift },
{ "l.srl", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 01-- 0x8",
EF(l_srl), 0, it_shift },
{ "l.sra", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 10-- 0x8",
EF(l_sra), 0, it_shift },
{ "l.ror", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 11-- 0x8", EFI,
0, it_shift },
{ "l.div", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-11 ---- 0x9",
EF(l_div), 0, it_arith },
{ "l.divu", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-11 ---- 0xA",
EF(l_divu), 0, it_arith },
{ "l.mulu", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-11 ---- 0xB", EFI,
0, it_arith },
{ "l.extbs", "rD,rA", "11 0x8 DDDDD AAAAA ---- --00 01-- 0xC",
EF(l_extbs), 0, it_move },
{ "l.exths", "rD,rA", "11 0x8 DDDDD AAAAA ---- --00 00-- 0xC",
EF(l_exths), 0, it_move },
{ "l.extws", "rD,rA", "11 0x8 DDDDD AAAAA ---- --00 00-- 0xD",
EF(l_extws), 0, it_move },
{ "l.extbz", "rD,rA", "11 0x8 DDDDD AAAAA ---- --00 11-- 0xC",
EF(l_extbz), 0, it_move },
{ "l.exthz", "rD,rA", "11 0x8 DDDDD AAAAA ---- --00 10-- 0xC",
EF(l_exthz), 0, it_move },
{ "l.extwz", "rD,rA", "11 0x8 DDDDD AAAAA ---- --00 01-- 0xD",
EF(l_extwz), 0, it_move },
{ "l.cmov", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 ---- 0xE",
EF(l_cmov), OR32_R_FLAG, it_move },
{ "l.ff1", "rD,rA", "11 0x8 DDDDD AAAAA ---- --00 ---- 0xF", EFI, 0,
it_arith },
 
{ "l.sfeq", "rA,rB", "11 0x9 00000 AAAAA BBBB B--- ---- ----",
EF(l_sfeq), OR32_W_FLAG, it_compare },
{ "l.sfne", "rA,rB", "11 0x9 00001 AAAAA BBBB B--- ---- ----",
EF(l_sfne), OR32_W_FLAG, it_compare },
{ "l.sfgtu", "rA,rB", "11 0x9 00010 AAAAA BBBB B--- ---- ----",
EF(l_sfgtu), OR32_W_FLAG, it_compare },
{ "l.sfgeu", "rA,rB", "11 0x9 00011 AAAAA BBBB B--- ---- ----",
EF(l_sfgeu), OR32_W_FLAG, it_compare },
{ "l.sfltu", "rA,rB", "11 0x9 00100 AAAAA BBBB B--- ---- ----",
EF(l_sfltu), OR32_W_FLAG, it_compare },
{ "l.sfleu", "rA,rB", "11 0x9 00101 AAAAA BBBB B--- ---- ----",
EF(l_sfleu), OR32_W_FLAG, it_compare },
{ "l.sfgts", "rA,rB", "11 0x9 01010 AAAAA BBBB B--- ---- ----",
EF(l_sfgts), OR32_W_FLAG, it_compare },
{ "l.sfges", "rA,rB", "11 0x9 01011 AAAAA BBBB B--- ---- ----",
EF(l_sfges), OR32_W_FLAG, it_compare },
{ "l.sflts", "rA,rB", "11 0x9 01100 AAAAA BBBB B--- ---- ----",
EF(l_sflts), OR32_W_FLAG, it_compare },
{ "l.sfles", "rA,rB", "11 0x9 01101 AAAAA BBBB B--- ---- ----",
EF(l_sfles), OR32_W_FLAG, it_compare },
 
{ "l.cust5", "rD,rA,rB,L,K", "11 0xC DDDDD AAAAA BBBB BLLL LLLK KKKK", EFI,
0, it_unknown },
{ "l.cust6", "", "11 0xD ----- ----- ---- ---- ---- ----", EFI,
0, it_unknown },
{ "l.cust7", "", "11 0xE ----- ----- ---- ---- ---- ----", EFI,
0, it_unknown },
{ "l.cust8", "", "11 0xF ----- ----- ---- ---- ---- ----", EFI,
0, it_unknown },
 
/* This section should not be defined in or1ksim, since it contains duplicates,
which would cause machine builder to complain. */
#ifdef HAS_CUST
{ "l.cust5_1", "rD", "11 0xC DDDDD ----- ---- ---- ---- ----", EFI,
0, it_unknown },
{ "l.cust5_2", "rD,rA" , "11 0xC DDDDD AAAAA ---- ---- ---- ----", EFI,
0, it_unknown },
{ "l.cust5_3", "rD,rA,rB", "11 0xC DDDDD AAAAA BBBB B--- ---- ----", EFI,
0, it_unknown },
 
{ "l.cust6_1", "rD", "11 0xD DDDDD ----- ---- ---- ---- ----", EFI,
0, it_unknown },
{ "l.cust6_2", "rD,rA" , "11 0xD DDDDD AAAAA ---- ---- ---- ----", EFI,
0, it_unknown },
{ "l.cust6_3", "rD,rA,rB", "11 0xD DDDDD AAAAA BBBB B--- ---- ----", EFI,
0, it_unknown },
 
{ "l.cust7_1", "rD", "11 0xE DDDDD ----- ---- ---- ---- ----", EFI,
0, it_unknown },
{ "l.cust7_2", "rD,rA" , "11 0xE DDDDD AAAAA ---- ---- ---- ----", EFI,
0, it_unknown },
{ "l.cust7_3", "rD,rA,rB", "11 0xE DDDDD AAAAA BBBB B--- ---- ----", EFI,
0, it_unknown },
 
{ "l.cust8_1", "rD", "11 0xF DDDDD ----- ---- ---- ---- ----", EFI,
0, it_unknown },
{ "l.cust8_2", "rD,rA" , "11 0xF DDDDD AAAAA ---- ---- ---- ----", EFI,
0, it_unknown },
{ "l.cust8_3", "rD,rA,rB", "11 0xF DDDDD AAAAA BBBB B--- ---- ----", EFI,
0, it_unknown },
#endif
 
{ "", "", "", EFI, 0, 0 } /* Dummy entry, not included in num_opcodes. This
* lets code examine entry i+1 without checking
* if we've run off the end of the table. */
};
 
#undef EFI
#undef EFN
#undef EF
 
/* **INDENT-ON** */
 
/* Define dummy, if debug is not defined. */
#ifndef HAS_DEBUG
#define debug(l, fmt...) ;
#endif
 
CONST int num_opcodes = ((sizeof(or32_opcodes)) / (sizeof(struct or32_opcode))) - 1;
 
/* Calculates instruction length in bytes. Always 4 for OR32. */
int
insn_len(int insn_index)
{
insn_index = 0; /* Just to get rid that warning. */
return 4;
}
 
/* Is individual insn's operand signed or unsigned? */
int
letter_signed(char l)
{
CONST struct or32_letter *pletter;
for(pletter = or32_letters; pletter->letter != '\0'; pletter++)
if (pletter->letter == l)
return pletter->sign;
printf("letter_signed(%c): Unknown letter.\n", l);
return 0;
}
 
/* Simple cache for letter ranges */
static int range_cache[256] = {0};
 
/* Number of letters in the individual lettered operand. */
int
letter_range(char l)
{
CONST struct or32_opcode *pinsn;
char *enc;
int range = 0;
 
/* Is value cached? */
if ((range = range_cache[(unsigned char)l])) return range;
for(pinsn = or32_opcodes; strlen(pinsn->name); pinsn++)
{
if (strchr(pinsn->encoding,l))
{
for (enc = pinsn->encoding; *enc != '\0'; enc++)
if ((*enc == '0') && (*(enc+1) == 'x'))
enc += 2;
else if (*enc == l)
range++;
return range_cache[(unsigned char)l] = range;
}
}
printf("\nABORT: letter_range(%c): Never used letter.\n", l);
exit(1);
}
 
/* MM: Returns index of given instruction name. */
int
insn_index (char *insn)
{
int i, found = -1;
for (i = 0; i < num_opcodes; i++)
if (!strcmp (or32_opcodes[i].name, insn))
{
found = i;
break;
}
return found;
}
 
/* Returns name of the specified instruction index */
CONST char *
insn_name(int index)
{
if (index >= 0 && index < num_opcodes)
return or32_opcodes[index].name;
else
return "???";
}
 
#if defined(HAS_EXECUTION) && SIMPLE_EXECUTION
void
l_none(struct iqueue_entry *current)
{
}
#elif defined(HAS_EXECUTION) && DYNAMIC_EXECUTION
void
l_none(struct op_queue *opq, int *param_t, orreg_t *param, int delay_slot)
{
}
#else
void
l_none()
{
}
#endif
 
/*** Finite automata for instruction decoding building code ***/
 
/* Find symbols in encoding. */
unsigned long
insn_extract(param_ch, enc_initial)
char param_ch;
char *enc_initial;
{
char *enc;
unsigned long ret = 0;
unsigned opc_pos = 32;
for (enc = enc_initial; *enc != '\0'; )
if ((*enc == '0') && (*(enc+1) == 'x'))
{
unsigned long tmp = strtol(enc+2, NULL, 16);
opc_pos -= 4;
if (param_ch == '0' || param_ch == '1')
{
if (param_ch == '0')
tmp = 15 - tmp;
ret |= tmp << opc_pos;
}
enc += 3;
}
else
{
if (*enc == '0' || *enc == '1' || *enc == '-' || isalpha(*enc) )
{
opc_pos--;
if (param_ch == *enc)
ret |= 1 << opc_pos;
}
enc++;
}
return ret;
}
 
#define MAX_AUTOMATA_SIZE (1200)
#define MAX_OP_TABLE_SIZE (1200)
#define MAX_LEN (8)
 
#ifndef MIN
# define MIN(x,y) ((x) < (y) ? (x) : (y))
#endif
 
unsigned long *automata;
int nuncovered;
int curpass = 0;
 
/* MM: Struct that holds runtime build information about instructions. */
struct temp_insn_struct *ti;
 
struct insn_op_struct *op_data, **op_start;
 
/* Recursive utility function used to find best match and to build automata. */
 
static unsigned long *
cover_insn (unsigned long *cur, int pass, unsigned int mask)
{
int best_first = 0, best_len = 0, i, last_match = -1, ninstr = 0;
unsigned long cur_mask = mask;
unsigned long *next;
 
for (i = 0; i < num_opcodes; i++)
if (ti[i].in_pass == pass)
{
cur_mask &= ti[i].insn_mask;
ninstr++;
last_match = i;
}
debug(8, "%08X %08X\n", mask, cur_mask);
if (ninstr == 0)
return 0;
if (ninstr == 1)
{
/* Leaf holds instruction index. */
debug(8, "%i>I%i %s\n", cur - automata, last_match, or32_opcodes[last_match].name);
*cur = LEAF_FLAG | last_match;
cur++;
nuncovered--;
} else {
/* Find longest match. */
for (i = 0; i < 32; i++)
{
int len;
for (len = best_len + 1; len < MIN(MAX_LEN, 33 - i); len++)
{
unsigned long m = (1UL << ((unsigned long)len)) - 1;
debug(9, " (%i(%08X & %08X>>%i = %08X, %08X)",len,m, cur_mask, i, (cur_mask >> (unsigned)i), (cur_mask >> (unsigned)i) & m);
if ((m & (cur_mask >> (unsigned)i)) == m)
{
best_len = len;
best_first = i;
debug(9, "!");
}
else
break;
}
}
debug(9, "\n");
if (!best_len)
{
fprintf (stderr, "%i instructions match mask 0x%08X:\n", ninstr, mask);
for (i = 0; i < num_opcodes; i++)
if (ti[i].in_pass == pass)
fprintf (stderr, "%s ", or32_opcodes[i].name);
fprintf (stderr, "\n");
exit (1);
}
debug(8, "%i> #### %i << %i (%i) ####\n", cur - automata, best_len, best_first, ninstr);
*cur = best_first;
cur++;
*cur = (1 << best_len) - 1;
cur++;
next = cur;
/* Allocate space for pointers. */
cur += 1 << best_len;
cur_mask = (1 << (unsigned long)best_len) - 1;
for (i = 0; i < (1 << (unsigned long)best_len); i++)
{
int j;
unsigned long *c;
curpass++;
for (j = 0; j < num_opcodes; j++)
if (ti[j].in_pass == pass
&& ((ti[j].insn >> best_first) & cur_mask) == (unsigned long) i
&& ((ti[j].insn_mask >> best_first) & cur_mask) == cur_mask)
ti[j].in_pass = curpass;
 
debug(9, "%08X %08X %i\n", mask, cur_mask, best_first);
c = cover_insn (cur, curpass, mask & (~(cur_mask << best_first)));
if (c)
{
debug(8, "%i> #%X -> %u\n", next - automata, i, cur - automata);
*next = cur - automata;
cur = c;
}
else
{
debug(8, "%i> N/A\n", next - automata);
*next = 0;
}
next++;
}
}
return cur;
}
 
/* Returns number of nonzero bits. */
static int
num_ones (unsigned long value)
{
int c = 0;
while (value)
{
if (value & 1)
c++;
value >>= 1;
}
return c;
}
 
/* Utility function, which converts parameters from or32_opcode format to more binary form.
Parameters are stored in ti struct. */
 
static struct insn_op_struct *
parse_params (CONST struct or32_opcode *opcode, struct insn_op_struct *cur)
{
char *args = opcode->args;
int i, type;
int num_cur_op = 0;;
i = 0;
type = 0;
/* In case we don't have any parameters, we add dummy read from r0. */
if (!(*args)) {
cur->type = OPTYPE_REG | OPTYPE_OP | OPTYPE_LAST;
cur->data = 0;
debug(9, "#%08X %08X\n", cur->type, cur->data);
cur++;
return cur;
}
while (*args != '\0')
{
if (*args == 'r')
{
args++;
type |= OPTYPE_REG;
if(args[1] == 'D')
type |= OPTYPE_DST;
}
else if (isalpha (*args))
{
unsigned long arg;
arg = insn_extract(*args, opcode->encoding);
debug(9, "%s : %08X ------\n", opcode->name, arg);
if (letter_signed (*args))
{
type |= OPTYPE_SIG;
type |= ((num_ones (arg) - 1) << OPTYPE_SBIT_SHR) & OPTYPE_SBIT;
}
 
num_cur_op = 0;
/* Split argument to sequences of consecutive ones. */
while (arg)
{
int shr = 0;
unsigned long tmp = arg, mask = 0;
while ((tmp & 1) == 0)
{
shr++;
tmp >>= 1;
}
while (tmp & 1)
{
mask++;
tmp >>= 1;
}
cur->type = type | shr;
cur->data = mask;
arg &= ~(((1 << mask) - 1) << shr);
debug(6, "|%08X %08X\n", cur->type, cur->data);
cur++;
num_cur_op++;
}
args++;
}
else if (*args == '(')
{
/* Next param is displacement. Later we will treat them as one operand. */
/* Set the OPTYPE_DIS flag on all insn_op_structs that belong to this
* operand */
while(num_cur_op > 0) {
cur[-num_cur_op].type |= type | OPTYPE_DIS;
num_cur_op--;
}
cur[-1].type |= OPTYPE_OP;
debug(9, ">%08X %08X\n", cur->type, cur->data);
type = 0;
i++;
args++;
}
else if (*args == OPERAND_DELIM)
{
cur--;
cur->type = type | cur->type | OPTYPE_OP;
debug(9, ">%08X %08X\n", cur->type, cur->data);
cur++;
type = 0;
i++;
args++;
}
else if (*args == '0')
{
cur->type = type;
cur->data = 0;
debug(9, ">%08X %08X\n", cur->type, cur->data);
cur++;
type = 0;
i++;
args++;
}
else if (*args == ')')
args++;
else
{
fprintf (stderr, "%s : parse error in args.\n", opcode->name);
exit (1);
}
}
cur--;
cur->type = type | cur->type | OPTYPE_OP | OPTYPE_LAST;
debug(9, "#%08X %08X\n", cur->type, cur->data);
cur++;
return cur;
}
 
/* Constructs new automata based on or32_opcodes array. */
 
void
build_automata()
{
int i;
unsigned long *end;
struct insn_op_struct *cur;
automata = (unsigned long *) malloc (MAX_AUTOMATA_SIZE * sizeof (unsigned long));
ti = (struct temp_insn_struct *) malloc (sizeof (struct temp_insn_struct) * num_opcodes);
 
nuncovered = num_opcodes;
 
#ifdef HAS_EXECUTION
printf("Building automata... ");
#endif
 
/* Build temporary information about instructions. */
for (i = 0; i < num_opcodes; i++)
{
unsigned long ones, zeros;
char *encoding = or32_opcodes[i].encoding;
ones = insn_extract('1', encoding);
zeros = insn_extract('0', encoding);
ti[i].insn_mask = ones | zeros;
ti[i].insn = ones;
ti[i].in_pass = curpass = 0;
/*debug(9, "%s: %s %08X %08X\n", or32_opcodes[i].name,
or32_opcodes[i].encoding, ti[i].insn_mask, ti[i].insn);*/
}
/* Until all are covered search for best criteria to separate them. */
end = cover_insn (automata, curpass, 0xFFFFFFFF);
if (end - automata > MAX_AUTOMATA_SIZE)
{
fprintf (stderr, "Automata too large. Increase MAX_AUTOMATA_SIZE.");
exit (1);
}
#ifdef HAS_EXECUTION
printf("done, num uncovered: %i/%i.\n", nuncovered, num_opcodes);
#endif
 
#ifdef HAS_EXECUTION
printf("Parsing operands data... ");
#endif
op_data = (struct insn_op_struct *) malloc (MAX_OP_TABLE_SIZE * sizeof (struct insn_op_struct));
op_start = (struct insn_op_struct **) malloc (num_opcodes * sizeof (struct insn_op_struct *));
cur = op_data;
for (i = 0; i < num_opcodes; i++)
{
op_start[i] = cur;
cur = parse_params (&or32_opcodes[i], cur);
if (cur - op_data > MAX_OP_TABLE_SIZE)
{
fprintf (stderr, "Operands table too small, increase MAX_OP_TABLE_SIZE.\n");
exit (1);
}
}
#ifdef HAS_EXECUTION
printf("done.\n");
#endif
}
 
void destruct_automata ()
{
free (ti);
free (automata);
free (op_data);
free (op_start);
}
 
/* Decodes instruction and returns instruction index. */
int insn_decode (unsigned int insn)
{
unsigned long *a = automata;
int i;
while (!(*a & LEAF_FLAG))
{
unsigned int first = *a;
//debug(9, "%i ", a - automata);
a++;
i = (insn >> first) & *a;
a++;
if (!*(a + i))
{ /* Invalid instruction found? */
//debug(9, "XXX\n", i);
return -1;
}
a = automata + *(a + i);
}
i = *a & ~LEAF_FLAG;
//debug(9, "%i\n", i);
/* Final check - do we have direct match?
(based on or32_opcodes this should be the only possibility,
but in case of invalid/missing instruction we must perform a check) */
if ((ti[i].insn_mask & insn) == ti[i].insn)
return i;
else
return -1;
}
 
static char disassembled_str[50];
char *disassembled = &disassembled_str[0];
 
/* Automagically does zero- or sign- extension and also finds correct
sign bit position if sign extension is correct extension. Which extension
is proper is figured out from letter description. */
unsigned long
extend_imm(unsigned long imm, char l)
{
unsigned long mask;
int letter_bits;
/* First truncate all bits above valid range for this letter
in case it is zero extend. */
letter_bits = letter_range(l);
mask = (1 << letter_bits) - 1;
imm &= mask;
/* Do sign extend if this is the right one. */
if (letter_signed(l) && (imm >> (letter_bits - 1)))
imm |= (~mask);
 
return imm;
}
 
unsigned long
or32_extract(param_ch, enc_initial, insn)
char param_ch;
char *enc_initial;
unsigned long insn;
{
char *enc;
unsigned long ret = 0;
int opc_pos = 0;
int param_pos = 0;
 
for (enc = enc_initial; *enc != '\0'; enc++)
if (*enc == param_ch)
{
if (enc - 2 >= enc_initial && (*(enc - 2) == '0') && (*(enc - 1) == 'x'))
continue;
else
param_pos++;
}
 
#if DEBUG
printf("or32_extract: %x ", param_pos);
#endif
opc_pos = 32;
for (enc = enc_initial; *enc != '\0'; )
if ((*enc == '0') && (*(enc+1) == 'x'))
{
opc_pos -= 4;
if ((param_ch == '0') || (param_ch == '1'))
{
unsigned long tmp = strtol(enc, NULL, 16);
#if DEBUG
printf(" enc=%s, tmp=%x ", enc, tmp);
#endif
if (param_ch == '0')
tmp = 15 - tmp;
ret |= tmp << opc_pos;
}
enc += 3;
}
else if ((*enc == '0') || (*enc == '1'))
{
opc_pos--;
if (param_ch == *enc)
ret |= 1 << opc_pos;
enc++;
}
else if (*enc == param_ch)
{
opc_pos--;
param_pos--;
#if DEBUG
printf("\n ret=%x opc_pos=%x, param_pos=%x\n", ret, opc_pos, param_pos);
#endif
if (islower(param_ch))
ret -= ((insn >> opc_pos) & 0x1) << param_pos;
else
ret += ((insn >> opc_pos) & 0x1) << param_pos;
enc++;
}
else if (isalpha(*enc))
{
opc_pos--;
enc++;
}
else if (*enc == '-')
{
opc_pos--;
enc++;
}
else
enc++;
 
#if DEBUG
printf ("ret=%x\n", ret);
#endif
return ret;
}
 
/* Print register. Used only by print_insn. */
 
static char *
or32_print_register (dest, param_ch, encoding, insn)
char *dest;
char param_ch;
char *encoding;
unsigned long insn;
{
int regnum = or32_extract(param_ch, encoding, insn);
sprintf (dest, "r%d", regnum);
while (*dest) dest++;
return dest;
}
 
/* Print immediate. Used only by print_insn. */
 
static char *
or32_print_immediate (dest, param_ch, encoding, insn)
char *dest;
char param_ch;
char *encoding;
unsigned long insn;
{
int imm = or32_extract (param_ch, encoding, insn);
 
imm = extend_imm(imm, param_ch);
if (letter_signed(param_ch))
{
if (imm < 0)
sprintf (dest, "%d", imm);
else
sprintf (dest, "0x%x", imm);
}
else
sprintf (dest, "%#x", imm);
while (*dest) dest++;
return dest;
}
 
/* Disassemble one instruction from insn to disassemble.
Return the size of the instruction. */
 
int
disassemble_insn (insn)
unsigned long insn;
{
return disassemble_index (insn, insn_decode (insn));
}
 
/* Disassemble one instruction from insn index.
Return the size of the instruction. */
 
int
disassemble_index (insn, index)
unsigned long insn;
int index;
{
char *dest = disassembled;
if (index >= 0)
{
struct or32_opcode const *opcode = &or32_opcodes[index];
char *s;
 
strcpy (dest, opcode->name);
while (*dest) dest++;
*dest++ = ' ';
*dest = 0;
for (s = opcode->args; *s != '\0'; ++s)
{
switch (*s)
{
case '\0':
return insn_len (insn);
 
case 'r':
dest = or32_print_register(dest, *++s, opcode->encoding, insn);
break;
 
default:
if (strchr (opcode->encoding, *s))
dest = or32_print_immediate (dest, *s, opcode->encoding, insn);
else {
*dest++ = *s;
*dest = 0;
}
}
}
}
else
{
/* This used to be %8x for binutils. */
sprintf(dest, ".word 0x%08lx", insn);
while (*dest) dest++;
}
return insn_len (insn);
}
/execute.c
0,0 → 1,821
/* execute.c -- OR1K architecture dependent simulation
Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
 
 
This file is part of OpenRISC 1000 Architectural Simulator.
 
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
/* Most of the OR1K simulation is done in here.
 
When SIMPLE_EXECUTION is defined below a file insnset.c is included!
*/
 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
 
#include "config.h"
 
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
 
#include "port.h"
#include "arch.h"
#include "branch_predict.h"
#include "abstract.h"
#include "labels.h"
#include "parse.h"
#include "except.h"
#include "sim-config.h"
#include "debug_unit.h"
#include "opcode/or32.h"
#include "spr_defs.h"
#include "execute.h"
#include "sprs.h"
#include "immu.h"
#include "dmmu.h"
#include "debug.h"
#include "stats.h"
#include "misc.h"
 
/* Current cpu state */
struct cpu_state cpu_state;
 
/* Benchmark multi issue execution */
int multissue[20];
int issued_per_cycle = 4;
 
/* Temporary program counter */
oraddr_t pcnext;
 
/* Store buffer analysis - stores are accumulated and commited when IO is idle */
static int sbuf_head = 0, sbuf_tail = 0, sbuf_count = 0;
static int sbuf_buf[MAX_SBUF_LEN] = {0};
static int sbuf_prev_cycles = 0;
 
/* Num cycles waiting for stores to complete */
int sbuf_wait_cyc = 0;
 
/* Number of total store cycles */
int sbuf_total_cyc = 0;
 
/* Whether we are doing statistical analysis */
int do_stats = 0;
 
/* Local data needed for execution. */
static int next_delay_insn;
static int breakpoint;
 
 
/* History of execution */
struct hist_exec *hist_exec_tail = NULL;
 
/* Implementation specific.
Get an actual value of a specific register. */
 
uorreg_t evalsim_reg(unsigned int regno)
{
if (regno < MAX_GPRS) {
return cpu_state.reg[regno];
} else {
PRINTF("\nABORT: read out of registers\n");
sim_done();
return 0;
}
}
 
/* Implementation specific.
Set a specific register with value. */
 
void setsim_reg(unsigned int regno, uorreg_t value)
{
if (regno == 0) /* gpr0 is always zero */
value = 0;
if (regno < MAX_GPRS) {
cpu_state.reg[regno] = value;
} else {
PRINTF("\nABORT: write out of registers\n");
sim_done();
}
}
 
/* Implementation specific.
Set a specific register with value. */
 
inline static void set_reg(int regno, uorreg_t value)
{
#if 0
if (strcmp(regstr, FRAME_REG) == 0) {
PRINTF("FP (%s) modified by insn at %x. ", FRAME_REG, cpu_state.pc);
PRINTF("Old:%.8lx New:%.8lx\n", eval_reg(regno), value);
}
if (strcmp(regstr, STACK_REG) == 0) {
PRINTF("SP (%s) modified by insn at %x. ", STACK_REG, cpu_state.pc);
PRINTF("Old:%.8lx New:%.8lx\n", eval_reg(regno), value);
}
#endif
 
if (regno < MAX_GPRS) {
cpu_state.reg[regno] = value;
#if RAW_RANGE_STATS
raw_stats.reg[regno] = runtime.sim.cycles;
#endif /* RAW_RANGE */
} else {
PRINTF("\nABORT: write out of registers\n");
sim_done();
}
}
 
/* Implementation specific.
Evaluates source operand opd. */
 
#if !(DYNAMIC_EXECUTION)
static
#endif
uorreg_t eval_operand_val(uint32_t insn, struct insn_op_struct *opd)
{
unsigned long operand = 0;
unsigned long sbit;
unsigned int nbits = 0;
 
while(1) {
operand |= ((insn >> (opd->type & OPTYPE_SHR)) & ((1 << opd->data) - 1)) << nbits;
nbits += opd->data;
 
if(opd->type & OPTYPE_OP)
break;
opd++;
}
 
if(opd->type & OPTYPE_SIG) {
sbit = (opd->type & OPTYPE_SBIT) >> OPTYPE_SBIT_SHR;
if(operand & (1 << sbit)) operand |= ~REG_C(0) << sbit;
}
 
return operand;
}
 
/* Does source operand depend on computation of dstoperand? Return
non-zero if yes.
 
Cycle t Cycle t+1
dst: irrelevant src: immediate always 0
dst: reg1 direct src: reg2 direct 0 if reg1 != reg2
dst: reg1 disp src: reg2 direct always 0
dst: reg1 direct src: reg2 disp 0 if reg1 != reg2
dst: reg1 disp src: reg2 disp always 1 (store must
finish before load)
dst: flag src: flag always 1
*/
 
static int check_depend(prev, next)
struct iqueue_entry *prev;
struct iqueue_entry *next;
{
/* Find destination type. */
unsigned long type = 0;
int prev_dis, next_dis;
orreg_t prev_reg_val = 0;
struct insn_op_struct *opd;
 
if (or32_opcodes[prev->insn_index].flags & OR32_W_FLAG
&& or32_opcodes[next->insn_index].flags & OR32_R_FLAG)
return 1;
 
opd = op_start[prev->insn_index];
prev_dis = 0;
 
while (1) {
if (opd->type & OPTYPE_DIS)
prev_dis = 1;
 
if (opd->type & OPTYPE_DST) {
type = opd->type;
if (prev_dis)
type |= OPTYPE_DIS;
/* Destination is always a register */
prev_reg_val = eval_operand_val (prev->insn, opd);
break;
}
if (opd->type & OPTYPE_LAST)
return 0; /* Doesn't have a destination operand */
if (opd->type & OPTYPE_OP)
prev_dis = 0;
opd++;
}
 
/* We search all source operands - if we find confict => return 1 */
opd = op_start[next->insn_index];
next_dis = 0;
 
while (1) {
if (opd->type & OPTYPE_DIS)
next_dis = 1;
/* This instruction sequence also depends on order of execution:
* l.lw r1, k(r1)
* l.sw k(r1), r4
* Here r1 is a destination in l.sw */
/* FIXME: This situation is not handeld here when r1 == r2:
* l.sw k(r1), r4
* l.lw r3, k(r2)
*/
if (!(opd->type & OPTYPE_DST) || (next_dis && (opd->type & OPTYPE_DST))) {
if (opd->type & OPTYPE_REG)
if (eval_operand_val (next->insn, opd) == prev_reg_val)
return 1;
}
if (opd->type & OPTYPE_LAST)
break;
opd++;
}
 
return 0;
}
 
/* Sets a new SPR_SR_OV value, based on next register value */
 
#if SET_OV_FLAG
#define set_ov_flag(value) \
if((value) & 0x80000000) \
cpu_state.sprs[SPR_SR] |= SPR_SR_OV; \
else \
cpu_state.sprs[SPR_SR] &= ~SPR_SR_OV
#else
#define set_ov_flag(value)
#endif
 
/* Modified by CZ 26/05/01 for new mode execution */
/* Fetch returns nonzero if instruction should NOT be executed. */
static inline int fetch(void)
{
static int break_just_hit = 0;
 
if (CHECK_BREAKPOINTS) {
/* MM: Check for breakpoint. This has to be done in fetch cycle,
because of peripheria.
MM1709: if we cannot access the memory entry, we could not set the
breakpoint earlier, so just check the breakpoint list. */
if (has_breakpoint (peek_into_itlb (cpu_state.pc)) && !break_just_hit) {
break_just_hit = 1;
return 1; /* Breakpoint set. */
}
break_just_hit = 0;
}
 
breakpoint = 0;
cpu_state.iqueue.insn_addr = cpu_state.pc;
cpu_state.iqueue.insn = eval_insn (cpu_state.pc, &breakpoint);
 
/* Fetch instruction. */
if (!except_pending)
runtime.cpu.instructions++;
 
/* update_pc will be called after execution */
 
return 0;
}
 
/* This code actually updates the PC value. */
static inline void update_pc (void)
{
cpu_state.delay_insn = next_delay_insn;
cpu_state.sprs[SPR_PPC] = cpu_state.pc; /* Store value for later */
cpu_state.pc = pcnext;
pcnext = cpu_state.delay_insn ? cpu_state.pc_delay : pcnext + 4;
}
 
#if SIMPLE_EXECUTION
static inline
#endif
void analysis (struct iqueue_entry *current)
{
if (config.cpu.dependstats) {
/* Dynamic, dependency stats. */
adddstats(cpu_state.icomplet.insn_index, current->insn_index, 1,
check_depend(&cpu_state.icomplet, current));
 
/* Dynamic, functional units stats. */
addfstats(or32_opcodes[cpu_state.icomplet.insn_index].func_unit,
or32_opcodes[current->insn_index].func_unit, 1,
check_depend(&cpu_state.icomplet, current));
 
/* Dynamic, single stats. */
addsstats(current->insn_index, 1);
}
 
if (config.cpu.superscalar) {
if ((or32_opcodes[current->insn_index].func_unit == it_branch) ||
(or32_opcodes[current->insn_index].func_unit == it_jump))
runtime.sim.storecycles += 0;
if (or32_opcodes[current->insn_index].func_unit == it_store)
runtime.sim.storecycles += 1;
if (or32_opcodes[current->insn_index].func_unit == it_load)
runtime.sim.loadcycles += 1;
#if 0
if ((cpu_state.icomplet.func_unit == it_load) &&
check_depend(&cpu_state.icomplet, current))
runtime.sim.loadcycles++;
#endif
/* Pseudo multiple issue benchmark */
if ((multissue[or32_opcodes[current->insn_index].func_unit] < 1) ||
(check_depend(&cpu_state.icomplet, current)) || (issued_per_cycle < 1)) {
int i;
for (i = 0; i < 20; i++)
multissue[i] = 2;
issued_per_cycle = 2;
runtime.cpu.supercycles++;
if (check_depend(&cpu_state.icomplet, current))
runtime.cpu.hazardwait++;
multissue[it_unknown] = 2;
multissue[it_shift] = 2;
multissue[it_compare] = 1;
multissue[it_branch] = 1;
multissue[it_jump] = 1;
multissue[it_extend] = 2;
multissue[it_nop] = 2;
multissue[it_move] = 2;
multissue[it_movimm] = 2;
multissue[it_arith] = 2;
multissue[it_store] = 2;
multissue[it_load] = 2;
}
multissue[or32_opcodes[current->insn_index].func_unit]--;
issued_per_cycle--;
}
if (config.cpu.dependstats)
/* Instruction waits in completition buffer until retired. */
memcpy (&cpu_state.icomplet, current, sizeof (struct iqueue_entry));
 
if (config.sim.history) {
/* History of execution */
hist_exec_tail = hist_exec_tail->next;
hist_exec_tail->addr = cpu_state.icomplet.insn_addr;
}
 
if (config.sim.exe_log) dump_exe_log();
}
 
/* Store buffer analysis - stores are accumulated and commited when IO is idle */
static inline void sbuf_store (int cyc) {
int delta = runtime.sim.cycles - sbuf_prev_cycles;
sbuf_total_cyc += cyc;
sbuf_prev_cycles = runtime.sim.cycles;
//PRINTF (">STORE %i,%i,%i,%i,%i\n", delta, sbuf_count, sbuf_tail, sbuf_head, sbuf_buf[sbuf_tail], sbuf_buf[sbuf_head]);
//PRINTF ("|%i,%i\n", sbuf_total_cyc, sbuf_wait_cyc);
/* Take stores from buffer, that occured meanwhile */
while (sbuf_count && delta >= sbuf_buf[sbuf_tail]) {
delta -= sbuf_buf[sbuf_tail];
sbuf_tail = (sbuf_tail + 1) % MAX_SBUF_LEN;
sbuf_count--;
}
if (sbuf_count)
sbuf_buf[sbuf_tail] -= delta;
 
/* Store buffer is full, take one out */
if (sbuf_count >= config.cpu.sbuf_len) {
sbuf_wait_cyc += sbuf_buf[sbuf_tail];
runtime.sim.mem_cycles += sbuf_buf[sbuf_tail];
sbuf_prev_cycles += sbuf_buf[sbuf_tail];
sbuf_tail = (sbuf_tail + 1) % MAX_SBUF_LEN;
sbuf_count--;
}
/* Put newest store in the buffer */
sbuf_buf[sbuf_head] = cyc;
sbuf_head = (sbuf_head + 1) % MAX_SBUF_LEN;
sbuf_count++;
//PRINTF ("|STORE %i,%i,%i,%i,%i\n", delta, sbuf_count, sbuf_tail, sbuf_head, sbuf_buf[sbuf_tail], sbuf_buf[sbuf_head]);
}
 
/* Store buffer analysis - previous stores should commit, before any load */
static inline void sbuf_load () {
int delta = runtime.sim.cycles - sbuf_prev_cycles;
sbuf_prev_cycles = runtime.sim.cycles;
//PRINTF (">LOAD %i,%i,%i,%i,%i\n", delta, sbuf_count, sbuf_tail, sbuf_head, sbuf_buf[sbuf_tail], sbuf_buf[sbuf_head]);
//PRINTF ("|%i,%i\n", sbuf_total_cyc, sbuf_wait_cyc);
/* Take stores from buffer, that occured meanwhile */
while (sbuf_count && delta >= sbuf_buf[sbuf_tail]) {
delta -= sbuf_buf[sbuf_tail];
sbuf_tail = (sbuf_tail + 1) % MAX_SBUF_LEN;
sbuf_count--;
}
if (sbuf_count)
sbuf_buf[sbuf_tail] -= delta;
 
/* Wait for all stores to complete */
while (sbuf_count > 0) {
sbuf_wait_cyc += sbuf_buf[sbuf_tail];
runtime.sim.mem_cycles += sbuf_buf[sbuf_tail];
sbuf_prev_cycles += sbuf_buf[sbuf_tail];
sbuf_tail = (sbuf_tail + 1) % MAX_SBUF_LEN;
sbuf_count--;
}
//PRINTF ("|LOAD %i,%i,%i,%i,%i\n", delta, sbuf_count, sbuf_tail, sbuf_head, sbuf_buf[sbuf_tail], sbuf_buf[sbuf_head]);
}
 
/* Outputs dissasembled instruction */
void dump_exe_log (void)
{
oraddr_t insn_addr = cpu_state.iqueue.insn_addr;
unsigned int i, j;
uorreg_t operand;
 
if (insn_addr == 0xffffffff) return;
if ((config.sim.exe_log_start <= runtime.cpu.instructions) &&
((config.sim.exe_log_end <= 0) ||
(runtime.cpu.instructions <= config.sim.exe_log_end))) {
if (config.sim.exe_log_marker &&
!(runtime.cpu.instructions % config.sim.exe_log_marker)) {
fprintf (runtime.sim.fexe_log, "--------------------- %8lli instruction ---------------------\n", runtime.cpu.instructions);
}
switch (config.sim.exe_log_type) {
case EXE_LOG_HARDWARE:
fprintf (runtime.sim.fexe_log, "\nEXECUTED(%11llu): %"PRIxADDR": ",
runtime.cpu.instructions, insn_addr);
fprintf (runtime.sim.fexe_log, "%.2x%.2x",
eval_direct8(insn_addr, 0, 0),
eval_direct8(insn_addr + 1, 0, 0));
fprintf (runtime.sim.fexe_log, "%.2x%.2x",
eval_direct8(insn_addr + 2, 0, 0),
eval_direct8(insn_addr + 3, 0 ,0));
for(i = 0; i < MAX_GPRS; i++) {
if (i % 4 == 0)
fprintf(runtime.sim.fexe_log, "\n");
fprintf (runtime.sim.fexe_log, "GPR%2u: %"PRIxREG" ", i,
cpu_state.reg[i]);
}
fprintf (runtime.sim.fexe_log, "\n");
fprintf (runtime.sim.fexe_log, "SR : %.8"PRIx32" ",
cpu_state.sprs[SPR_SR]);
fprintf (runtime.sim.fexe_log, "EPCR0: %"PRIxADDR" ",
cpu_state.sprs[SPR_EPCR_BASE]);
fprintf (runtime.sim.fexe_log, "EEAR0: %"PRIxADDR" ",
cpu_state.sprs[SPR_EEAR_BASE]);
fprintf (runtime.sim.fexe_log, "ESR0 : %.8"PRIx32"\n",
cpu_state.sprs[SPR_ESR_BASE]);
break;
case EXE_LOG_SIMPLE:
case EXE_LOG_SOFTWARE:
{
extern char *disassembled;
disassemble_index (cpu_state.iqueue.insn, cpu_state.iqueue.insn_index);
{
struct label_entry *entry;
entry = get_label(insn_addr);
if (entry)
fprintf (runtime.sim.fexe_log, "%s:\n", entry->name);
}
 
if (config.sim.exe_log_type == EXE_LOG_SOFTWARE) {
struct insn_op_struct *opd = op_start[cpu_state.iqueue.insn_index];
j = 0;
while (1) {
operand = eval_operand_val (cpu_state.iqueue.insn, opd);
while (!(opd->type & OPTYPE_OP))
opd++;
if (opd->type & OPTYPE_DIS) {
fprintf (runtime.sim.fexe_log, "EA =%"PRIxADDR" PA =%"PRIxADDR" ",
cpu_state.insn_ea, peek_into_dtlb(cpu_state.insn_ea,0,0));
opd++; /* Skip of register operand */
j++;
} else if ((opd->type & OPTYPE_REG) && operand) {
fprintf (runtime.sim.fexe_log, "r%-2i=%"PRIxREG" ",
(int)operand, evalsim_reg (operand));
} else
fprintf (runtime.sim.fexe_log, " ");
j++;
if(opd->type & OPTYPE_LAST)
break;
opd++;
}
if(or32_opcodes[cpu_state.iqueue.insn_index].flags & OR32_R_FLAG) {
fprintf (runtime.sim.fexe_log, "SR =%08x",
cpu_state.sprs[SPR_SR]);
j++;
}
while(j < 3) {
fprintf (runtime.sim.fexe_log, " ");
j++;
}
}
fprintf (runtime.sim.fexe_log, "%"PRIxADDR" ", insn_addr);
fprintf (runtime.sim.fexe_log, "%s\n", disassembled);
}
}
}
}
 
/* Dump registers - 'r' or 't' command */
void dumpreg()
{
int i;
oraddr_t physical_pc;
 
if ((physical_pc = peek_into_itlb(cpu_state.iqueue.insn_addr))) {
/*
* PRINTF("\t\t\tEA: %08x <--> PA: %08x\n", cpu_state.iqueue.insn_addr, physical_pc);
*/
dumpmemory(physical_pc, physical_pc + 4, 1, 0);
}
else {
PRINTF("INTERNAL SIMULATOR ERROR:\n");
PRINTF("no translation for currently executed instruction\n");
}
// generate_time_pretty (temp, runtime.sim.cycles * config.sim.clkcycle_ps);
PRINTF(" (executed) [cycle %lld, #%lld]\n", runtime.sim.cycles,
runtime.cpu.instructions);
if (config.cpu.superscalar)
PRINTF ("Superscalar CYCLES: %u", runtime.cpu.supercycles);
if (config.cpu.hazards)
PRINTF (" HAZARDWAIT: %u\n", runtime.cpu.hazardwait);
else
if (config.cpu.superscalar)
PRINTF ("\n");
 
if ((physical_pc = peek_into_itlb(cpu_state.pc))) {
/*
* PRINTF("\t\t\tEA: %08x <--> PA: %08x\n", cpu_state.pc, physical_pc);
*/
dumpmemory(physical_pc, physical_pc + 4, 1, 0);
}
else
PRINTF("%"PRIxADDR": : xxxxxxxx ITLB miss follows", cpu_state.pc);
PRINTF(" (next insn) %s", (cpu_state.delay_insn?"(delay insn)":""));
for(i = 0; i < MAX_GPRS; i++) {
if (i % 4 == 0)
PRINTF("\n");
PRINTF("GPR%.2u: %"PRIxREG" ", i, evalsim_reg(i));
}
PRINTF("flag: %u\n", cpu_state.sprs[SPR_SR] & SPR_SR_F ? 1 : 0);
}
 
/* Generated/built in decoding/executing function */
static inline void decode_execute (struct iqueue_entry *current);
 
/* Wrapper around real decode_execute function -- some statistics here only */
static inline void decode_execute_wrapper (struct iqueue_entry *current)
{
breakpoint = 0;
 
#ifndef HAS_EXECUTION
#error HAS_EXECUTION has to be defined in order to execute programs.
#endif
/* FIXME: Most of this file is not needed with DYNAMIC_EXECUTION */
#if !(DYNAMIC_EXECUTION)
decode_execute (current);
#endif
#if SET_OV_FLAG
/* Check for range exception */
if((cpu_state.sprs[SPR_SR] & SPR_SR_OVE) &&
(cpu_state.sprs[SPR_SR] & SPR_SR_OV))
except_handle (EXCEPT_RANGE, cpu_state.sprs[SPR_EEAR_BASE]);
#endif
 
if(breakpoint)
except_handle(EXCEPT_TRAP, cpu_state.sprs[SPR_EEAR_BASE]);
}
 
/* Reset the CPU */
void cpu_reset(void)
{
int i;
struct hist_exec *hist_exec_head = NULL;
struct hist_exec *hist_exec_new;
 
runtime.sim.cycles = 0;
runtime.sim.loadcycles = 0;
runtime.sim.storecycles = 0;
runtime.cpu.instructions = 0;
runtime.cpu.supercycles = 0;
runtime.cpu.hazardwait = 0;
for (i = 0; i < MAX_GPRS; i++)
set_reg (i, 0);
memset(&cpu_state.iqueue, 0, sizeof(cpu_state.iqueue));
memset(&cpu_state.icomplet, 0, sizeof(cpu_state.icomplet));
sbuf_head = 0;
sbuf_tail = 0;
sbuf_count = 0;
sbuf_prev_cycles = 0;
 
/* Initialise execution history circular buffer */
for (i = 0; i < HISTEXEC_LEN; i++) {
hist_exec_new = malloc(sizeof(struct hist_exec));
if(!hist_exec_new) {
fprintf(stderr, "Out-of-memory\n");
exit(1);
}
if(!hist_exec_head)
hist_exec_head = hist_exec_new;
else
hist_exec_tail->next = hist_exec_new;
 
hist_exec_new->prev = hist_exec_tail;
hist_exec_tail = hist_exec_new;
}
/* Make hist_exec_tail->next point to hist_exec_head */
hist_exec_tail->next = hist_exec_head;
hist_exec_head->prev = hist_exec_tail;
 
/* Cpu configuration */
cpu_state.sprs[SPR_UPR] = config.cpu.upr;
cpu_state.sprs[SPR_VR] = config.cpu.rev & SPR_VR_REV;
cpu_state.sprs[SPR_VR] |= config.cpu.ver << 16;
cpu_state.sprs[SPR_SR] = config.cpu.sr;
 
pcnext = 0x0; /* MM1409: All programs should start at reset vector entry! */
if (config.sim.verbose) PRINTF ("Starting at 0x%"PRIxADDR"\n", pcnext);
cpu_state.pc = pcnext;
pcnext += 4;
debug(1, "reset ...\n");
 
#if DYNAMIC_EXECUTION
cpu_state.ts_current = 1;
#endif
/* MM1409: All programs should set their stack pointer! */
except_handle(EXCEPT_RESET, 0);
update_pc();
except_pending = 0;
}
 
/* Simulates one CPU clock cycle */
inline int cpu_clock ()
{
except_pending = 0;
next_delay_insn = 0;
if(fetch()) {
PRINTF ("Breakpoint hit.\n");
return 1;
}
 
if(except_pending) {
update_pc();
except_pending = 0;
return 0;
}
 
if(breakpoint) {
except_handle(EXCEPT_TRAP, cpu_state.sprs[SPR_EEAR_BASE]);
update_pc();
except_pending = 0;
return 0;
}
 
decode_execute_wrapper (&cpu_state.iqueue);
update_pc();
return 0;
}
 
/* If decoding cannot be found, call this function */
#if SIMPLE_EXECUTION
void l_invalid (struct iqueue_entry *current) {
#else
void l_invalid () {
#endif
except_handle(EXCEPT_ILLEGAL, cpu_state.iqueue.insn_addr);
}
 
#if COMPLEX_EXECUTION
 
/* Include decode_execute function */
#include "execgen.c"
 
#elif SIMPLE_EXECUTION
 
 
#define INSTRUCTION(name) void name (struct iqueue_entry *current)
 
/* Implementation specific.
Get an actual value of a specific register. */
 
static uorreg_t eval_reg(unsigned int regno)
{
if (regno < MAX_GPRS) {
#if RAW_RANGE_STATS
int delta = (runtime.sim.cycles - raw_stats.reg[regno]);
if ((unsigned long)delta < (unsigned long)MAX_RAW_RANGE)
raw_stats.range[delta]++;
#endif /* RAW_RANGE */
return cpu_state.reg[regno];
} else {
PRINTF("\nABORT: read out of registers\n");
sim_done();
return 0;
}
}
 
/* Implementation specific.
Evaluates source operand op_no. */
 
static uorreg_t eval_operand (int op_no, unsigned long insn_index, uint32_t insn)
{
struct insn_op_struct *opd = op_start[insn_index];
uorreg_t ret;
 
while (op_no) {
if(opd->type & OPTYPE_LAST) {
fprintf (stderr, "Instruction requested more operands than it has\n");
exit (1);
}
if((opd->type & OPTYPE_OP) && !(opd->type & OPTYPE_DIS))
op_no--;
opd++;
}
 
if (opd->type & OPTYPE_DIS) {
ret = eval_operand_val (insn, opd);
while (!(opd->type & OPTYPE_OP))
opd++;
opd++;
ret += eval_reg (eval_operand_val (insn, opd));
cpu_state.insn_ea = ret;
return ret;
}
if (opd->type & OPTYPE_REG)
return eval_reg (eval_operand_val (insn, opd));
 
return eval_operand_val (insn, opd);
}
 
/* Implementation specific.
Set destination operand (reister direct) with value. */
inline static void set_operand(int op_no, orreg_t value,
unsigned long insn_index, uint32_t insn)
{
struct insn_op_struct *opd = op_start[insn_index];
 
while (op_no) {
if(opd->type & OPTYPE_LAST) {
fprintf (stderr, "Instruction requested more operands than it has\n");
exit (1);
}
if((opd->type & OPTYPE_OP) && !(opd->type & OPTYPE_DIS))
op_no--;
opd++;
}
 
if (!(opd->type & OPTYPE_REG)) {
fprintf (stderr, "Trying to set a non-register operand\n");
exit (1);
}
set_reg (eval_operand_val (insn, opd), value);
}
 
/* Simple and rather slow decoding function based on built automata. */
static inline void decode_execute (struct iqueue_entry *current)
{
int insn_index;
current->insn_index = insn_index = insn_decode(current->insn);
 
if (insn_index < 0)
l_invalid(current);
else {
or32_opcodes[insn_index].exec(current);
}
 
if (do_stats) analysis(&cpu_state.iqueue);
}
 
#define SET_PARAM0(val) set_operand(0, val, current->insn_index, current->insn)
 
#define PARAM0 eval_operand(0, current->insn_index, current->insn)
#define PARAM1 eval_operand(1, current->insn_index, current->insn)
#define PARAM2 eval_operand(2, current->insn_index, current->insn)
 
#include "insnset.c"
 
#elif defined(DYNAMIC_EXECUTION)
 
#else
# error "One of SIMPLE_EXECUTION/COMPLEX_EXECUTION must be defined"
#endif
/insnset.c
0,0 → 1,599
/* execute.c -- Instruction specific functions.
Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
2000-2002 Marko Mlinar, markom@opencores.org
 
This file is part of OpenRISC 1000 Architectural Simulator.
 
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
INSTRUCTION (l_add) {
orreg_t temp1, temp2, temp3;
int8_t temp4;
temp2 = (orreg_t)PARAM2;
temp3 = (orreg_t)PARAM1;
temp1 = temp2 + temp3;
SET_PARAM0(temp1);
set_ov_flag (temp1);
if (ARITH_SET_FLAG) {
if(!temp1)
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
else
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
}
if ((uorreg_t) temp1 < (uorreg_t) temp2)
cpu_state.sprs[SPR_SR] |= SPR_SR_CY;
else
cpu_state.sprs[SPR_SR] &= ~SPR_SR_CY;
 
temp4 = temp1;
if (temp4 == temp1)
or1k_mstats.byteadd++;
}
INSTRUCTION (l_addc) {
orreg_t temp1, temp2, temp3;
int8_t temp4;
temp2 = (orreg_t)PARAM2;
temp3 = (orreg_t)PARAM1;
temp1 = temp2 + temp3;
if(cpu_state.sprs[SPR_SR] & SPR_SR_CY)
temp1++;
SET_PARAM0(temp1);
set_ov_flag (temp1);
if (ARITH_SET_FLAG) {
if(!temp1)
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
else
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
}
if ((uorreg_t) temp1 < (uorreg_t) temp2)
cpu_state.sprs[SPR_SR] |= SPR_SR_CY;
else
cpu_state.sprs[SPR_SR] &= ~SPR_SR_CY;
 
temp4 = temp1;
if (temp4 == temp1)
or1k_mstats.byteadd++;
}
INSTRUCTION (l_sw) {
int old_cyc = 0;
if (config.cpu.sbuf_len) old_cyc = runtime.sim.mem_cycles;
set_mem32(PARAM0, PARAM1, &breakpoint);
if (config.cpu.sbuf_len) {
int t = runtime.sim.mem_cycles;
runtime.sim.mem_cycles = old_cyc;
sbuf_store (t - old_cyc);
}
}
INSTRUCTION (l_sb) {
int old_cyc = 0;
if (config.cpu.sbuf_len) old_cyc = runtime.sim.mem_cycles;
set_mem8(PARAM0, PARAM1, &breakpoint);
if (config.cpu.sbuf_len) {
int t = runtime.sim.mem_cycles;
runtime.sim.mem_cycles = old_cyc;
sbuf_store (t- old_cyc);
}
}
INSTRUCTION (l_sh) {
int old_cyc = 0;
if (config.cpu.sbuf_len) old_cyc = runtime.sim.mem_cycles;
set_mem16(PARAM0, PARAM1, &breakpoint);
if (config.cpu.sbuf_len) {
int t = runtime.sim.mem_cycles;
runtime.sim.mem_cycles = old_cyc;
sbuf_store (t - old_cyc);
}
}
INSTRUCTION (l_lwz) {
uint32_t val;
if (config.cpu.sbuf_len) sbuf_load ();
val = eval_mem32(PARAM1, &breakpoint);
/* If eval operand produced exception don't set anything */
if (!except_pending)
SET_PARAM0(val);
}
INSTRUCTION (l_lbs) {
int8_t val;
if (config.cpu.sbuf_len) sbuf_load ();
val = eval_mem8(PARAM1, &breakpoint);
/* If eval opreand produced exception don't set anything */
if (!except_pending)
SET_PARAM0(val);
}
INSTRUCTION (l_lbz) {
uint8_t val;
if (config.cpu.sbuf_len) sbuf_load ();
val = eval_mem8(PARAM1, &breakpoint);
/* If eval opreand produced exception don't set anything */
if (!except_pending)
SET_PARAM0(val);
}
INSTRUCTION (l_lhs) {
int16_t val;
if (config.cpu.sbuf_len) sbuf_load ();
val = eval_mem16(PARAM1, &breakpoint);
/* If eval opreand produced exception don't set anything */
if (!except_pending)
SET_PARAM0(val);
}
INSTRUCTION (l_lhz) {
uint16_t val;
if (config.cpu.sbuf_len) sbuf_load ();
val = eval_mem16(PARAM1, &breakpoint);
/* If eval opreand produced exception don't set anything */
if (!except_pending)
SET_PARAM0(val);
}
INSTRUCTION (l_movhi) {
SET_PARAM0(PARAM1 << 16);
}
INSTRUCTION (l_and) {
uorreg_t temp1;
temp1 = PARAM1 & PARAM2;
set_ov_flag (temp1);
SET_PARAM0(temp1);
if (ARITH_SET_FLAG) {
if(!temp1)
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
else
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
}
}
INSTRUCTION (l_or) {
uorreg_t temp1;
temp1 = PARAM1 | PARAM2;
set_ov_flag (temp1);
SET_PARAM0(temp1);
}
INSTRUCTION (l_xor) {
uorreg_t temp1;
temp1 = PARAM1 ^ PARAM2;
set_ov_flag (temp1);
SET_PARAM0(temp1);
}
INSTRUCTION (l_sub) {
orreg_t temp1;
temp1 = (orreg_t)PARAM1 - (orreg_t)PARAM2;
set_ov_flag (temp1);
SET_PARAM0(temp1);
}
/*int mcount = 0;*/
INSTRUCTION (l_mul) {
orreg_t temp1;
temp1 = (orreg_t)PARAM1 * (orreg_t)PARAM2;
set_ov_flag (temp1);
SET_PARAM0(temp1);
/*if (!(mcount++ & 1023)) {
PRINTF ("[%i]\n",mcount);
}*/
}
INSTRUCTION (l_div) {
orreg_t temp3, temp2, temp1;
temp3 = PARAM2;
temp2 = PARAM1;
if (temp3)
temp1 = temp2 / temp3;
else {
except_handle(EXCEPT_ILLEGAL, cpu_state.pc);
return;
}
set_ov_flag (temp1);
SET_PARAM0(temp1);
}
INSTRUCTION (l_divu) {
uorreg_t temp3, temp2, temp1;
temp3 = PARAM2;
temp2 = PARAM1;
if (temp3)
temp1 = temp2 / temp3;
else {
except_handle(EXCEPT_ILLEGAL, cpu_state.pc);
return;
}
set_ov_flag (temp1);
SET_PARAM0(temp1);
/* runtime.sim.cycles += 16; */
}
INSTRUCTION (l_sll) {
uorreg_t temp1;
 
temp1 = PARAM1 << PARAM2;
set_ov_flag (temp1);
SET_PARAM0(temp1);
/* runtime.sim.cycles += 2; */
}
INSTRUCTION (l_sra) {
orreg_t temp1;
temp1 = (orreg_t)PARAM1 >> PARAM2;
set_ov_flag (temp1);
SET_PARAM0(temp1);
/* runtime.sim.cycles += 2; */
}
INSTRUCTION (l_srl) {
uorreg_t temp1;
temp1 = PARAM1 >> PARAM2;
set_ov_flag (temp1);
SET_PARAM0(temp1);
/* runtime.sim.cycles += 2; */
}
INSTRUCTION (l_bf) {
if (config.bpb.enabled) {
int fwd = (PARAM0 >= cpu_state.pc) ? 1 : 0;
or1k_mstats.bf[cpu_state.sprs[SPR_SR] & SPR_SR_F ? 1 : 0][fwd]++;
bpb_update(current->insn_addr, cpu_state.sprs[SPR_SR] & SPR_SR_F ? 1 : 0);
}
if(cpu_state.sprs[SPR_SR] & SPR_SR_F) {
cpu_state.pc_delay = cpu_state.pc + (orreg_t)PARAM0 * 4;
btic_update(pcnext);
next_delay_insn = 1;
} else {
btic_update(cpu_state.pc);
}
}
INSTRUCTION (l_bnf) {
if (config.bpb.enabled) {
int fwd = (PARAM0 >= cpu_state.pc) ? 1 : 0;
or1k_mstats.bnf[cpu_state.sprs[SPR_SR] & SPR_SR_F ? 0 : 1][fwd]++;
bpb_update(current->insn_addr, cpu_state.sprs[SPR_SR] & SPR_SR_F ? 0 : 1);
}
if (!(cpu_state.sprs[SPR_SR] & SPR_SR_F)) {
cpu_state.pc_delay = cpu_state.pc + (orreg_t)PARAM0 * 4;
btic_update(pcnext);
next_delay_insn = 1;
} else {
btic_update(cpu_state.pc);
}
}
INSTRUCTION (l_j) {
cpu_state.pc_delay = cpu_state.pc + (orreg_t)PARAM0 * 4;
next_delay_insn = 1;
}
INSTRUCTION (l_jal) {
cpu_state.pc_delay = cpu_state.pc + (orreg_t)PARAM0 * 4;
set_reg(LINK_REGNO, cpu_state.pc + 8);
next_delay_insn = 1;
if (config.sim.profile) {
struct label_entry *tmp;
if (verify_memoryarea(cpu_state.pc_delay) && (tmp = get_label (cpu_state.pc_delay)))
fprintf (runtime.sim.fprof, "+%08llX %"PRIxADDR" %"PRIxADDR" %s\n",
runtime.sim.cycles, cpu_state.pc + 8, cpu_state.pc_delay,
tmp->name);
else
fprintf (runtime.sim.fprof, "+%08llX %"PRIxADDR" %"PRIxADDR" @%"PRIxADDR"\n",
runtime.sim.cycles, cpu_state.pc + 8, cpu_state.pc_delay,
cpu_state.pc_delay);
}
}
INSTRUCTION (l_jalr) {
cpu_state.pc_delay = PARAM0;
set_reg(LINK_REGNO, cpu_state.pc + 8);
next_delay_insn = 1;
}
INSTRUCTION (l_jr) {
cpu_state.pc_delay = PARAM0;
next_delay_insn = 1;
if (config.sim.profile)
fprintf (runtime.sim.fprof, "-%08llX %"PRIxADDR"\n", runtime.sim.cycles,
cpu_state.pc_delay);
}
INSTRUCTION (l_rfe) {
pcnext = cpu_state.sprs[SPR_EPCR_BASE];
mtspr(SPR_SR, cpu_state.sprs[SPR_ESR_BASE]);
}
INSTRUCTION (l_nop) {
oraddr_t stackaddr;
uint32_t k = PARAM0;
switch (k) {
case NOP_NOP:
break;
case NOP_EXIT:
PRINTF("exit(%"PRIdREG")\n", evalsim_reg (3));
fprintf(stderr, "@reset : cycles %lld, insn #%lld\n",
runtime.sim.reset_cycles, runtime.cpu.reset_instructions);
fprintf(stderr, "@exit : cycles %lld, insn #%lld\n", runtime.sim.cycles,
runtime.cpu.instructions);
fprintf(stderr, " diff : cycles %lld, insn #%lld\n",
runtime.sim.cycles - runtime.sim.reset_cycles,
runtime.cpu.instructions - runtime.cpu.reset_instructions);
if (config.debug.gdb_enabled)
set_stall_state (1);
else
sim_done();
break;
case NOP_CNT_RESET:
PRINTF("****************** counters reset ******************\n");
PRINTF("cycles %lld, insn #%lld\n", runtime.sim.cycles, runtime.cpu.instructions);
PRINTF("****************** counters reset ******************\n");
runtime.sim.reset_cycles = runtime.sim.cycles;
runtime.cpu.reset_instructions = runtime.cpu.instructions;
break;
case NOP_PRINTF:
stackaddr = evalsim_reg(4);
simprintf(stackaddr, evalsim_reg(3));
debug(5, "simprintf %x\n", stackaddr);
break;
case NOP_REPORT:
PRINTF("report(0x%"PRIxREG");\n", evalsim_reg(3));
default:
if (k >= NOP_REPORT_FIRST && k <= NOP_REPORT_LAST)
PRINTF("report %i (0x%"PRIxREG");\n", k - NOP_REPORT_FIRST,
evalsim_reg(3));
break;
}
}
INSTRUCTION (l_sfeq) {
if(PARAM0 == PARAM1)
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
else
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
}
INSTRUCTION (l_sfne) {
if(PARAM0 != PARAM1)
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
else
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
}
INSTRUCTION (l_sfgts) {
if((orreg_t)PARAM0 > (orreg_t)PARAM1)
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
else
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
}
INSTRUCTION (l_sfges) {
if((orreg_t)PARAM0 >= (orreg_t)PARAM1)
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
else
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
}
INSTRUCTION (l_sflts) {
if((orreg_t)PARAM0 < (orreg_t)PARAM1)
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
else
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
}
INSTRUCTION (l_sfles) {
if((orreg_t)PARAM0 <= (orreg_t)PARAM1)
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
else
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
}
INSTRUCTION (l_sfgtu) {
if(PARAM0 > PARAM1)
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
else
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
}
INSTRUCTION (l_sfgeu) {
if(PARAM0 >= PARAM1)
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
else
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
}
INSTRUCTION (l_sfltu) {
if(PARAM0 < PARAM1)
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
else
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
}
INSTRUCTION (l_sfleu) {
if(PARAM0 <= PARAM1)
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
else
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
}
INSTRUCTION (l_extbs) {
int8_t x;
x = PARAM1;
SET_PARAM0((orreg_t)x);
}
INSTRUCTION (l_extbz) {
uint8_t x;
x = PARAM1;
SET_PARAM0((uorreg_t)x);
}
INSTRUCTION (l_exths) {
int16_t x;
x = PARAM1;
SET_PARAM0((orreg_t)x);
}
INSTRUCTION (l_exthz) {
uint16_t x;
x = PARAM1;
SET_PARAM0((uorreg_t)x);
}
INSTRUCTION (l_extws) {
int32_t x;
x = PARAM1;
SET_PARAM0((orreg_t)x);
}
INSTRUCTION (l_extwz) {
uint32_t x;
x = PARAM1;
SET_PARAM0((uorreg_t)x);
}
INSTRUCTION (l_mtspr) {
uint16_t regno = PARAM0 + PARAM2;
uorreg_t value = PARAM1;
 
if (cpu_state.sprs[SPR_SR] & SPR_SR_SM)
mtspr(regno, value);
else {
PRINTF("WARNING: trying to write SPR while SR[SUPV] is cleared.\n");
sim_done();
}
}
INSTRUCTION (l_mfspr) {
uint16_t regno = PARAM1 + PARAM2;
uorreg_t value = mfspr(regno);
 
if (cpu_state.sprs[SPR_SR] & SPR_SR_SM)
SET_PARAM0(value);
else {
SET_PARAM0(0);
PRINTF("WARNING: trying to read SPR while SR[SUPV] is cleared.\n");
sim_done();
}
}
INSTRUCTION (l_sys) {
except_handle(EXCEPT_SYSCALL, cpu_state.sprs[SPR_EEAR_BASE]);
}
INSTRUCTION (l_trap) {
/* TODO: some SR related code here! */
except_handle(EXCEPT_TRAP, cpu_state.sprs[SPR_EEAR_BASE]);
}
INSTRUCTION (l_mac) {
uorreg_t lo, hi;
LONGEST l;
orreg_t x, y;
 
lo = cpu_state.sprs[SPR_MACLO];
hi = cpu_state.sprs[SPR_MACHI];
x = PARAM0;
y = PARAM1;
PRINTF ("[%"PRIxREG",%"PRIxREG"]\t", x, y);
l = (ULONGEST)lo | ((LONGEST)hi << 32);
l += (LONGEST) x * (LONGEST) y;
 
/* This implementation is very fast - it needs only one cycle for mac. */
lo = ((ULONGEST)l) & 0xFFFFFFFF;
hi = ((LONGEST)l) >> 32;
cpu_state.sprs[SPR_MACLO] = lo;
cpu_state.sprs[SPR_MACHI] = hi;
PRINTF ("(%"PRIxREG",%"PRIxREG"\n", hi, lo);
}
INSTRUCTION (l_msb) {
uorreg_t lo, hi;
LONGEST l;
orreg_t x, y;
 
lo = cpu_state.sprs[SPR_MACLO];
hi = cpu_state.sprs[SPR_MACHI];
x = PARAM0;
y = PARAM1;
 
PRINTF ("[%"PRIxREG",%"PRIxREG"]\t", x, y);
 
l = (ULONGEST)lo | ((LONGEST)hi << 32);
l -= x * y;
 
/* This implementation is very fast - it needs only one cycle for msb. */
lo = ((ULONGEST)l) & 0xFFFFFFFF;
hi = ((LONGEST)l) >> 32;
cpu_state.sprs[SPR_MACLO] = lo;
cpu_state.sprs[SPR_MACHI] = hi;
PRINTF ("(%"PRIxREG",%"PRIxREG")\n", hi, lo);
}
INSTRUCTION (l_macrc) {
uorreg_t lo, hi;
LONGEST l;
/* No need for synchronization here -- all MAC instructions are 1 cycle long. */
lo = cpu_state.sprs[SPR_MACLO];
hi = cpu_state.sprs[SPR_MACHI];
l = (ULONGEST) lo | ((LONGEST)hi << 32);
l >>= 28;
//PRINTF ("<%08x>\n", (unsigned long)l);
SET_PARAM0((orreg_t)l);
cpu_state.sprs[SPR_MACLO] = 0;
cpu_state.sprs[SPR_MACHI] = 0;
}
INSTRUCTION (l_cmov) {
SET_PARAM0(cpu_state.sprs[SPR_SR] & SPR_SR_F ? PARAM1 : PARAM2);
}
INSTRUCTION (l_ff1) {
SET_PARAM0(ffs(PARAM1));
}
/******* Floating point instructions *******/
/* Single precision */
INSTRUCTION (lf_add_s) {
SET_PARAM0((float)PARAM1 + (float)PARAM2);
}
INSTRUCTION (lf_div_s) {
SET_PARAM0((float)PARAM1 / (float)PARAM2);
}
INSTRUCTION (lf_ftoi_s) {
// set_operand32(0, freg[get_operand(1)], &breakpoint);
}
INSTRUCTION (lf_itof_s) {
// freg[get_operand(0)] = eval_operand32(1, &breakpoint);
}
INSTRUCTION (lf_madd_s) {
SET_PARAM0((float)PARAM0 + (float)PARAM1 * (float)PARAM2);
}
INSTRUCTION (lf_mul_s) {
SET_PARAM0((float)PARAM1 * (float)PARAM2);
}
INSTRUCTION (lf_rem_s) {
float temp = (float)PARAM1 / (float)PARAM2;
SET_PARAM0(temp - (uint32_t)temp);
}
INSTRUCTION (lf_sfeq_s) {
if((float)PARAM0 == (float)PARAM1)
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
else
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
}
INSTRUCTION (lf_sfge_s) {
if((float)PARAM0 >= (float)PARAM1)
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
else
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
}
INSTRUCTION (lf_sfgt_s) {
if((float)PARAM0 > (float)PARAM1)
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
else
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
}
INSTRUCTION (lf_sfle_s) {
if((float)PARAM0 <= (float)PARAM1)
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
else
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
}
INSTRUCTION (lf_sflt_s) {
if((float)PARAM0 < (float)PARAM1)
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
else
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
}
INSTRUCTION (lf_sfne_s) {
if((float)PARAM0 != (float)PARAM1)
cpu_state.sprs[SPR_SR] |= SPR_SR_F;
else
cpu_state.sprs[SPR_SR] &= ~SPR_SR_F;
}
INSTRUCTION (lf_sub_s) {
SET_PARAM0((float)PARAM1 - (float)PARAM2);
}
 
/******* Custom instructions *******/
INSTRUCTION (l_cust1) {
/*int destr = current->insn >> 21;
int src1r = current->insn >> 15;
int src2r = current->insn >> 9;*/
}
INSTRUCTION (l_cust2) {
}
INSTRUCTION (l_cust3) {
}
INSTRUCTION (l_cust4) {
}
insnset.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: dyn_rec_stubs.c =================================================================== --- dyn_rec_stubs.c (nonexistent) +++ dyn_rec_stubs.c (revision 1765) @@ -0,0 +1,270 @@ +/* dyn_rec_stubs.c -- Stubs to allow the recompiler to be run standalone + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* Stubs to test the recompiler */ +#include +#include +#include +#include +#include +#include + +#include "arch.h" +#include "immu.h" +#include "spr_defs.h" +#include "opcode/or32.h" +#include "abstract.h" +#include "execute.h" +#include "sim-config.h" +#include "sched.h" + +#include "i386_regs.h" +#include "dyn_rec.h" + +#define PAGE_LEN 8192 + +int do_stats = 0; + +/* NOTE: Directly copied from execute.c */ +uorreg_t eval_operand_val(uint32_t insn, struct insn_op_struct *opd) +{ + unsigned long operand = 0; + unsigned long sbit; + unsigned int nbits = 0; + + while(1) { + operand |= ((insn >> (opd->type & OPTYPE_SHR)) & ((1 << opd->data) - 1)) << nbits; + nbits += opd->data; + + if(opd->type & OPTYPE_OP) + break; + opd++; + } + + if(opd->type & OPTYPE_SIG) { + sbit = (opd->type & OPTYPE_SBIT) >> OPTYPE_SBIT_SHR; + if(operand & (1 << sbit)) operand |= ~REG_C(0) << sbit; + } + + return operand; +} + +oraddr_t immu_translate(oraddr_t virtaddr) +{ + return virtaddr; +} + +oraddr_t peek_into_itlb(oraddr_t virtaddr) +{ + return virtaddr; +} + +void do_scheduler() +{ + return; +} + +static uint32_t page[PAGE_LEN / 4]; + +uint32_t eval_insn(oraddr_t addr, int *brkp) +{ + if(addr >= PAGE_LEN) { + fprintf(stderr, "DR is trying to access memory outside the boundries of a page %08x\n", addr); + return 0; + } + + return bswap_32(page[addr / 4]); +} + +int main(int argc, char **argv) +{ + FILE *f; + long len; + int i; + struct dyn_page *dp; + long off = 0; + + if((argc < 3) || (argc > 4)) { + fprintf(stderr, "Usage: %s [offset into the file]\n", + argv[0]); + return 1; + } + + if(argc == 4) + off = strtol(argv[3], NULL, 0); + + f = fopen(argv[1], "r"); + if(!f) { + fprintf(stderr, "Unable to open %s: %s\n", argv[1], strerror(errno)); + return 1; + } + + if(fseek(f, 0, SEEK_END)) { + fprintf(stderr, "Uanble to seek to the end of the file %s: %s\n", argv[1], + strerror(errno)); + return 1; + } + + len = ftell(f); + + if(len == -1) { + fprintf(stderr, "Unable to determine file length: %s\n", strerror(errno)); + return 1; + } + + fseek(f, off, SEEK_SET); + + if((len - off) < PAGE_LEN) { + printf("File is less than 1 page long, padding with zeros.\n"); + fread(page, len, 1, f); + /* Pad the page with zeros */ + for(i = len; i < PAGE_LEN; i++) + page[i] = 0; + } else + fread(page, PAGE_LEN, 1, f); + + fclose(f); + + build_automata(); + init_dyn_recomp(); + + dp = new_dp(0); + + /* Cool, recompile the page */ + fprintf(stderr, "Hold on a sec, I'm recompileing the given page...\n"); + + recompile_page(dp); + + fprintf(stderr, "Recompiled page length: %i\n", dp->host_len); + fprintf(stderr, "Recompiled to: %p\n", dp->host_page); + fprintf(stderr, "Dumping reced page to disk...\n"); + + f = fopen(argv[2], "w"); + fwrite(dp->host_page, dp->host_len, 1, f); + fclose(f); + +/* + printf("--- Recompiled or disassembly ---\n"); + for(i = 0; i < 2048; i++) { + extern char *disassembled; + disassemble_insn(eval_insn(i * 4, NULL)); + if(!eval_insn(i * 4, NULL)) continue; + printf("%04x: %08x %s\n", i * 4, eval_insn(i * 4, NULL), disassembled); + } + printf("--- Recompiled or disassembly end ---\n"); +*/ + + printf("--- Recompiled offsets ---\n"); + for(i = 0; i < (PAGE_LEN / 4); i++) + printf("%"PRIxADDR": %x\n", i * 4, dp->locs[i] - dp->host_page); + printf("--- Recompiled offsets end ---\n"); + destruct_automata(); + + return 0; +} + +/* Lame linker stubs. These are only referenced in the recompiled code */ +struct cpu_state cpu_state; +struct runtime runtime; +struct scheduler_struct scheduler; +struct config config; +int immu_ex_from_insn; + +/* FIXME: eval_insn should become this */ +uint32_t eval_insn_direct(oraddr_t memaddr, int through_mmu) +{ + return 0; +} + +uint32_t eval_direct32(oraddr_t memaddr, int through_mmu, int through_dc) +{ + return 0; +} + +uint32_t eval_mem32(oraddr_t addr, int *breakpoint) +{ + return 0; +} + +uint16_t eval_mem16(oraddr_t addr, int *breakpoint) +{ + return 0; +} + +uint8_t eval_mem8(oraddr_t addr, int *breakpoint) +{ + return 0; +} + +void set_mem32(oraddr_t addr, uint32_t val, int *breakpoint) +{ +} + +void set_mem16(oraddr_t addr, uint16_t val, int *breakpoint) +{ +} + +void set_mem8(oraddr_t addr, uint8_t val, int *breakpoint) +{ +} + +void analysis(struct iqueue_entry *current) +{ +} + +void mtspr(uint16_t regno, const uorreg_t value) +{ +} + +unsigned long spr_read_ttcr(void) +{ + return 0; +} + +void debug(int level, const char *format,...) +{ +} + +void simprintf(oraddr_t stackaddr, unsigned long regparam) +{ +} + +const char *except_name(oraddr_t except) +{ + return NULL; +} + +uorreg_t mfspr(const uint16_t regno) +{ + return 0; +} + +static struct dev_memarea dummy_area = { + ops: { delayr: 1 }, +}; + +struct dev_memarea *verify_memoryarea(oraddr_t addr) +{ + return &dummy_area; +} + +void sim_done (void) +{ +} Index: dyn_rec.c =================================================================== --- dyn_rec.c (nonexistent) +++ dyn_rec.c (revision 1765) @@ -0,0 +1,3019 @@ +/* dyn_rec.c -- Dynamic recompiler implementation for or32 + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" + +#ifdef HAVE_INTTYPES_H +#include +#endif + +#include "port.h" +#include "arch.h" +#include "immu.h" +#include "abstract.h" +#include "opcode/or32.h" +#include "spr_defs.h" +#include "execute.h" +#include "except.h" +#include "spr_defs.h" +#include "sim-config.h" +#include "sched.h" + +#include "rec_i386.h" +#include "i386_regs.h" + +#include "dyn_rec.h" +#include "gen_ops.h" + +#include "op_support.h" + +/* NOTE: All openrisc (or) addresses in this file are *PHYSICAL* addresses */ + +/* FIXME: Optimise sorted list adding */ + +typedef void (*generic_gen_op)(struct op_queue *opq, int end); +typedef void (*imm_gen_op)(struct op_queue *opq, int end, uorreg_t imm); + +void gen_l_invalid(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot); + +static const generic_gen_op gen_op_move_gpr_t[NUM_T_REGS][32] = { + { NULL, + gen_op_move_gpr1_t0, + gen_op_move_gpr2_t0, + gen_op_move_gpr3_t0, + gen_op_move_gpr4_t0, + gen_op_move_gpr5_t0, + gen_op_move_gpr6_t0, + gen_op_move_gpr7_t0, + gen_op_move_gpr8_t0, + gen_op_move_gpr9_t0, + gen_op_move_gpr10_t0, + gen_op_move_gpr11_t0, + gen_op_move_gpr12_t0, + gen_op_move_gpr13_t0, + gen_op_move_gpr14_t0, + gen_op_move_gpr15_t0, + gen_op_move_gpr16_t0, + gen_op_move_gpr17_t0, + gen_op_move_gpr18_t0, + gen_op_move_gpr19_t0, + gen_op_move_gpr20_t0, + gen_op_move_gpr21_t0, + gen_op_move_gpr22_t0, + gen_op_move_gpr23_t0, + gen_op_move_gpr24_t0, + gen_op_move_gpr25_t0, + gen_op_move_gpr26_t0, + gen_op_move_gpr27_t0, + gen_op_move_gpr28_t0, + gen_op_move_gpr29_t0, + gen_op_move_gpr30_t0, + gen_op_move_gpr31_t0 }, + { NULL, + gen_op_move_gpr1_t1, + gen_op_move_gpr2_t1, + gen_op_move_gpr3_t1, + gen_op_move_gpr4_t1, + gen_op_move_gpr5_t1, + gen_op_move_gpr6_t1, + gen_op_move_gpr7_t1, + gen_op_move_gpr8_t1, + gen_op_move_gpr9_t1, + gen_op_move_gpr10_t1, + gen_op_move_gpr11_t1, + gen_op_move_gpr12_t1, + gen_op_move_gpr13_t1, + gen_op_move_gpr14_t1, + gen_op_move_gpr15_t1, + gen_op_move_gpr16_t1, + gen_op_move_gpr17_t1, + gen_op_move_gpr18_t1, + gen_op_move_gpr19_t1, + gen_op_move_gpr20_t1, + gen_op_move_gpr21_t1, + gen_op_move_gpr22_t1, + gen_op_move_gpr23_t1, + gen_op_move_gpr24_t1, + gen_op_move_gpr25_t1, + gen_op_move_gpr26_t1, + gen_op_move_gpr27_t1, + gen_op_move_gpr28_t1, + gen_op_move_gpr29_t1, + gen_op_move_gpr30_t1, + gen_op_move_gpr31_t1 }, + { NULL, + gen_op_move_gpr1_t2, + gen_op_move_gpr2_t2, + gen_op_move_gpr3_t2, + gen_op_move_gpr4_t2, + gen_op_move_gpr5_t2, + gen_op_move_gpr6_t2, + gen_op_move_gpr7_t2, + gen_op_move_gpr8_t2, + gen_op_move_gpr9_t2, + gen_op_move_gpr10_t2, + gen_op_move_gpr11_t2, + gen_op_move_gpr12_t2, + gen_op_move_gpr13_t2, + gen_op_move_gpr14_t2, + gen_op_move_gpr15_t2, + gen_op_move_gpr16_t2, + gen_op_move_gpr17_t2, + gen_op_move_gpr18_t2, + gen_op_move_gpr19_t2, + gen_op_move_gpr20_t2, + gen_op_move_gpr21_t2, + gen_op_move_gpr22_t2, + gen_op_move_gpr23_t2, + gen_op_move_gpr24_t2, + gen_op_move_gpr25_t2, + gen_op_move_gpr26_t2, + gen_op_move_gpr27_t2, + gen_op_move_gpr28_t2, + gen_op_move_gpr29_t2, + gen_op_move_gpr30_t2, + gen_op_move_gpr31_t2 } }; + +static const generic_gen_op gen_op_move_t_gpr[NUM_T_REGS][32] = { + { NULL, + gen_op_move_t0_gpr1, + gen_op_move_t0_gpr2, + gen_op_move_t0_gpr3, + gen_op_move_t0_gpr4, + gen_op_move_t0_gpr5, + gen_op_move_t0_gpr6, + gen_op_move_t0_gpr7, + gen_op_move_t0_gpr8, + gen_op_move_t0_gpr9, + gen_op_move_t0_gpr10, + gen_op_move_t0_gpr11, + gen_op_move_t0_gpr12, + gen_op_move_t0_gpr13, + gen_op_move_t0_gpr14, + gen_op_move_t0_gpr15, + gen_op_move_t0_gpr16, + gen_op_move_t0_gpr17, + gen_op_move_t0_gpr18, + gen_op_move_t0_gpr19, + gen_op_move_t0_gpr20, + gen_op_move_t0_gpr21, + gen_op_move_t0_gpr22, + gen_op_move_t0_gpr23, + gen_op_move_t0_gpr24, + gen_op_move_t0_gpr25, + gen_op_move_t0_gpr26, + gen_op_move_t0_gpr27, + gen_op_move_t0_gpr28, + gen_op_move_t0_gpr29, + gen_op_move_t0_gpr30, + gen_op_move_t0_gpr31 }, + { NULL, + gen_op_move_t1_gpr1, + gen_op_move_t1_gpr2, + gen_op_move_t1_gpr3, + gen_op_move_t1_gpr4, + gen_op_move_t1_gpr5, + gen_op_move_t1_gpr6, + gen_op_move_t1_gpr7, + gen_op_move_t1_gpr8, + gen_op_move_t1_gpr9, + gen_op_move_t1_gpr10, + gen_op_move_t1_gpr11, + gen_op_move_t1_gpr12, + gen_op_move_t1_gpr13, + gen_op_move_t1_gpr14, + gen_op_move_t1_gpr15, + gen_op_move_t1_gpr16, + gen_op_move_t1_gpr17, + gen_op_move_t1_gpr18, + gen_op_move_t1_gpr19, + gen_op_move_t1_gpr20, + gen_op_move_t1_gpr21, + gen_op_move_t1_gpr22, + gen_op_move_t1_gpr23, + gen_op_move_t1_gpr24, + gen_op_move_t1_gpr25, + gen_op_move_t1_gpr26, + gen_op_move_t1_gpr27, + gen_op_move_t1_gpr28, + gen_op_move_t1_gpr29, + gen_op_move_t1_gpr30, + gen_op_move_t1_gpr31 }, + { NULL, + gen_op_move_t2_gpr1, + gen_op_move_t2_gpr2, + gen_op_move_t2_gpr3, + gen_op_move_t2_gpr4, + gen_op_move_t2_gpr5, + gen_op_move_t2_gpr6, + gen_op_move_t2_gpr7, + gen_op_move_t2_gpr8, + gen_op_move_t2_gpr9, + gen_op_move_t2_gpr10, + gen_op_move_t2_gpr11, + gen_op_move_t2_gpr12, + gen_op_move_t2_gpr13, + gen_op_move_t2_gpr14, + gen_op_move_t2_gpr15, + gen_op_move_t2_gpr16, + gen_op_move_t2_gpr17, + gen_op_move_t2_gpr18, + gen_op_move_t2_gpr19, + gen_op_move_t2_gpr20, + gen_op_move_t2_gpr21, + gen_op_move_t2_gpr22, + gen_op_move_t2_gpr23, + gen_op_move_t2_gpr24, + gen_op_move_t2_gpr25, + gen_op_move_t2_gpr26, + gen_op_move_t2_gpr27, + gen_op_move_t2_gpr28, + gen_op_move_t2_gpr29, + gen_op_move_t2_gpr30, + gen_op_move_t2_gpr31 } }; + +static const imm_gen_op calc_insn_ea_table[NUM_T_REGS] = + { gen_op_calc_insn_ea_t0, gen_op_calc_insn_ea_t1, gen_op_calc_insn_ea_t2 }; + +/* Linker stubs. This will allow the linker to link in op.o. The relocations + * that the linker does for these will be irrelevent anyway, since we patch the + * relocations during recompilation. */ +uorreg_t __op_param1; +uorreg_t __op_param2; +uorreg_t __op_param3; + +/* The number of bytes that a dynamicly recompiled page should be enlarged by */ +#define RECED_PAGE_ENLARGE_BY 51200 + +/* The number of entries that the micro operations array in op_queue should be + * enlarged by */ +#define OPS_ENLARGE_BY 5 + +#define T_NONE (-1) + +void *rec_stack_base; + +/* FIXME: Put this into some header */ +extern int do_stats; + +static int sigsegv_state = 0; +static void *sigsegv_addr = NULL; + +void dyn_ret_stack_prot(void); + +void dyn_sigsegv_debug(int u, siginfo_t *siginf, void *dat) +{ + struct dyn_page *dp; + FILE *f; + char filen[18]; /* 18 == strlen("or_page.%08x") + 1 */ + void *stack; + int i, j; + void *trace[11]; + int num_trace; + char **trace_names; + struct sigcontext *sigc = dat; + + if(!sigsegv_state) { + sigsegv_addr = siginf->si_addr; + } else { + fprintf(stderr, "Nested SIGSEGV occured, dumping next chuck of info\n"); + sigsegv_state++; + } + + /* First dump all the data that does not need dereferenceing to get */ + switch(sigsegv_state) { + case 0: + fflush(stderr); + fprintf(stderr, "Segmentation fault on acces to %p at 0x%08lx, (or address: 0x%"PRIxADDR")\n\n", + sigsegv_addr, sigc->eip, get_pc()); + sigsegv_state++; + case 1: + /* Run through the recompiled pages, dumping them to disk as we go */ + for(i = 0; i < (2 << (32 - config.dmmu.pagesize_log2)); i++) { + dp = cpu_state.dyn_pages[i]; + if(!dp) + continue; + fprintf(stderr, "Dumping%s page 0x%"PRIxADDR" recompiled to %p (len: %u) to disk\n", + dp->dirty ? " dirty" : "", dp->or_page, dp->host_page, + dp->host_len); + fflush(stdout); + + sprintf(filen, "or_page.%"PRIxADDR, dp->or_page); + if(!(f = fopen(filen, "w"))) { + fprintf(stderr, "Unable to open %s to dump the recompiled page to: %s\n", + filen, strerror(errno)); + continue; + } + if(fwrite(dp->host_page, dp->host_len, 1, f) < 1) + fprintf(stderr, "Unable to write recompiled data to file: %s\n", + strerror(errno)); + + fclose(f); + } + sigsegv_state++; + case 2: + /* Dump the contents of the stack */ + fprintf(stderr, "Stack dump: "); + fflush(stderr); + + num_trace = backtrace(trace, 10); + + trace[num_trace++] = (void *)sigc->eip; + trace_names = backtrace_symbols(trace, num_trace); + + stack = get_sp(); + fprintf(stderr, "(of stack at %p, base: %p)\n", stack, rec_stack_base); + fflush(stderr); + for(i = 0; stack < rec_stack_base; i++, stack += 4) { + fprintf(stderr, " <%i> 0x%08x", i, *(uint32_t *)stack); + /* Try to find a symbolic name with this entry */ + for(j = 0; j < num_trace; j++) { + if(trace[j] == *(void **)stack) + fprintf(stderr, " <%s>", trace_names[j]); + } + fprintf(stderr, "\n"); + fflush(stderr); + } + fprintf(stderr, "Fault at: 0x%08lx <%s>\n", sigc->eip, + trace_names[num_trace - 1]); + sigsegv_state++; + case 3: + sim_done(); + } +} + +struct dyn_page *new_dp(oraddr_t page) +{ + struct dyn_page *dp = malloc(sizeof(struct dyn_page)); + dp->or_page = IADDR_PAGE(page); + + dp->locs = malloc(sizeof(void *) * (config.immu.pagesize / 4)); + + dp->host_len = 0; + dp->host_page = NULL; + dp->dirty = 1; + + cpu_state.dyn_pages[dp->or_page >> config.immu.pagesize_log2] = dp; + return dp; +} + +/* This is called whenever the immu is either enabled/disabled or reconfigured + * while enabled. This checks if an itlb miss would occour and updates the immu + * hit delay counter */ +void recheck_immu(int got_en_dis) +{ + oraddr_t addr = get_pc(); + extern int immu_ex_from_insn; + + if(cpu_state.delay_insn) { + /* If an instruction pagefault or an ITLB miss would occur, it must appear + * to have come from the jumped-to address */ + if(IADDR_PAGE(addr) == IADDR_PAGE(cpu_state.pc_delay)) { + immu_ex_from_insn = 1; + immu_translate(addr + 4); + immu_ex_from_insn = 0; + runtime.sim.mem_cycles = 0; + } + return; + } + + if(IADDR_PAGE(addr) == IADDR_PAGE(addr + 4)) { + /* If the next instruction is on another page then the immu will be checked + * when the jump to the next page happens */ + immu_ex_from_insn = 1; + immu_translate(addr + 4); + immu_ex_from_insn = 0; + /* If we had am immu hit then runtime.sim.mem_cycles will hold the value + * config.immu.hitdelay, but this value is added to the cycle when the next + * instruction is run */ + runtime.sim.mem_cycles = 0; + } + /* Only update the cycle decrementer if the mmu got enabled or disabled */ + if(got_en_dis == IMMU_GOT_ENABLED) + /* Add the mmu hit delay to the cycle counter */ + upd_cycles_dec(cpu_state.curr_page->delayr - config.immu.hitdelay); + else if(got_en_dis == IMMU_GOT_DISABLED) { + upd_cycles_dec(cpu_state.curr_page->delayr); + /* Since we updated the cycle decrementer above the immu hit delay will not + * be added to the cycle counter for this instruction. Compensate for this + * by adding it now */ + /* FIXME: This is not correct here. In the complex execution model the hit + * delay is added to runtime.sim.mem_cycles which is only joined with the + * cycle counter after analysis() and before the scheduler would run. + * Therefore the scheduler will still be correct but analysis() will produce + * wrong results just for this one instruction. */ + add_to_cycles(config.immu.hitdelay); + } +} + +/* Runs the scheduler. Called from except_handler (and dirtyfy_page below) */ +void run_sched_out_of_line(int add_normal) +{ + oraddr_t pc = get_pc(); + extern int immu_ex_from_insn; + + if(!cpu_state.ts_current) + upd_reg_from_t(pc, 0); + + if(add_normal && do_stats) { + cpu_state.iqueue.insn_addr = pc; + cpu_state.iqueue.insn = eval_insn_direct(pc, !immu_ex_from_insn); + cpu_state.iqueue.insn_index = insn_decode(cpu_state.iqueue.insn); + runtime.cpu.instructions++; + analysis(&cpu_state.iqueue); + } + + /* Run the scheduler */ + if(add_normal) + sched_add_cycles(); + + op_join_mem_cycles(); + upd_sim_cycles(); + if(scheduler.job_queue->time <= 0) + do_scheduler(); +} + +/* Signals a page as dirty */ +static void dirtyfy_page(struct dyn_page *dp) +{ + oraddr_t check; + + printf("Dirtyfying page 0x%"PRIxADDR"\n", dp->or_page); + + dp->dirty = 1; + + /* If the execution is currently in the page that was touched then recompile + * it now and jump back to the point of execution */ + check = cpu_state.delay_insn ? cpu_state.pc_delay : get_pc() + 4; + if(IADDR_PAGE(check) == dp->or_page) { + run_sched_out_of_line(1); + recompile_page(dp); + + cpu_state.delay_insn = 0; + + /* Jump out to the next instruction */ + do_jump(check); + } +} + +/* Checks to see if a write happened to a recompiled page. If so marks it as + * dirty */ +void dyn_checkwrite(oraddr_t addr) +{ + /* FIXME: Do this with mprotect() */ + struct dyn_page *dp = cpu_state.dyn_pages[addr >> config.immu.pagesize_log2]; + + /* Since the locations 0x0-0xff are nearly always written to in an exception + * handler, ignore any writes to these locations. If code ends up jumping + * out there, we'll recompile when the jump actually happens. */ + if((addr > 0x100) && dp && !dp->dirty) + dirtyfy_page(dp); +} + +static void ship_gprs_out_t(struct op_queue *opq, int end, unsigned int *reg_t) +{ + int i; + + /* Before takeing the temporaries out, temporarily remove the op_do_sched + * operation such that dyn_page->ts_bound shall be correct before the + * scheduler runs */ + if(end && opq->num_ops && (opq->ops[opq->num_ops - 1] == op_do_sched_indx)) { + opq->num_ops--; + ship_gprs_out_t(opq, end, reg_t); + gen_op_do_sched(opq, 1); + return; + } + + for(i = 0; i < NUM_T_REGS; i++) { + if(reg_t[i] < 32) + gen_op_move_gpr_t[i][reg_t[i]](opq, end); + } +} + +static int find_unused_t(unsigned int *pres_t, unsigned int *reg_t) +{ + int empty = -1; /* Invalid */ + int i; + + /* Try to find a temporary that does not contain a register and is not + * needed to be preserved */ + for(i = 0; i < NUM_T_REGS; i++) { + if(!pres_t[i]) { + empty = i; + if(reg_t[i] > 31) + return i; + } + } + return empty; +} + +/* Checks if there is enough space in dp->host_page, if not grow it */ +void *enough_host_page(struct dyn_page *dp, void *cur, unsigned int *len, + unsigned int amount) +{ + unsigned int used = cur - dp->host_page; + + /* The array is long enough */ + if((used + amount) <= *len) + return cur; + + /* Reallocate */ + *len += RECED_PAGE_ENLARGE_BY; + + if(!(dp->host_page = realloc(dp->host_page, *len))) { + fprintf(stderr, "OOM\n"); + exit(1); + } + + return dp->host_page + used; +} + +/* Adds an operation to the opq */ +void add_to_opq(struct op_queue *opq, int end, int op) +{ + if(opq->num_ops == opq->ops_len) { + opq->ops_len += OPS_ENLARGE_BY; + if(!(opq->ops = realloc(opq->ops, opq->ops_len * sizeof(int)))) { + fprintf(stderr, "OOM\n"); + exit(1); + } + } + + if(end) + opq->ops[opq->num_ops] = op; + else { + /* Shift everything over by one */ + memmove(opq->ops + 1, opq->ops, opq->num_ops* sizeof(int)); + opq->ops[0] = op; + } + + opq->num_ops++; +} + +static void gen_op_mark_loc(struct op_queue *opq, int end) +{ + add_to_opq(opq, end, op_mark_loc_indx); +} + +/* Adds a parameter to the opq */ +void add_to_op_params(struct op_queue *opq, int end, unsigned long param) +{ + if(opq->num_ops_param == opq->ops_param_len) { + opq->ops_param_len += OPS_ENLARGE_BY; + if(!(opq->ops_param = realloc(opq->ops_param, opq->ops_param_len * sizeof(int)))) { + fprintf(stderr, "OOM\n"); + exit(1); + } + } + + if(end) + opq->ops_param[opq->num_ops_param] = param; + else { + /* Shift everything over by one */ + memmove(opq->ops_param + 1, opq->ops_param, opq->num_ops_param); + opq->ops_param[0] = param; + } + + opq->num_ops_param++; +} + +/* Function to guard against rogue ret instructions in the operations */ +void dyn_ret_stack_prot(void) +{ + fprintf(stderr, "An operation (I have no clue which) has a ret statement in it\n"); + fprintf(stderr, "Good luck debugging it!\n"); + + exit(1); +} + +/* Jumps out to some Openrisc address */ +void jump_dyn_code(oraddr_t addr) +{ + set_pc(addr); + do_jump(addr); +} + +/* Initialises the recompiler */ +void init_dyn_recomp(void) +{ + struct sigaction sigact; + struct op_queue *opq; + unsigned int i; + + cpu_state.opqs = NULL; + + /* Allocate the operation queue list (+1 for the page chaining) */ + for(i = 0; i < (config.immu.pagesize / 4) + 1; i++) { + if(!(opq = malloc(sizeof(struct op_queue)))) { + fprintf(stderr, "OOM\n"); + exit(1); + } + + /* initialise some fields */ + opq->ops_len = 0; + opq->ops = NULL; + opq->ops_param_len = 0; + opq->ops_param = NULL; + opq->xref = 0; + + if(cpu_state.opqs) + cpu_state.opqs->prev = opq; + + opq->next = cpu_state.opqs; + cpu_state.opqs = opq; + } + + opq->prev = NULL; + + /* Just some value that we'll use as the base for our stack */ + rec_stack_base = get_sp(); + + cpu_state.curr_page = NULL; + if(!(cpu_state.dyn_pages = malloc(sizeof(void *) * (2 << (32 - + config.immu.pagesize_log2))))) { + fprintf(stderr, "OOM\n"); + exit(1); + } + memset(cpu_state.dyn_pages, 0, + sizeof(void *) * (2 << (32 - config.immu.pagesize_log2))); + + /* Register our segmentation fault handler */ + sigact.sa_sigaction = dyn_sigsegv_debug; + memset(&sigact.sa_mask, 0, sizeof(sigact.sa_mask)); + sigact.sa_flags = SA_SIGINFO | SA_NOMASK; + if(sigaction(SIGSEGV, &sigact, NULL)) + printf("WARN: Unable to install SIGSEGV handler! Don't expect to be able to debug the recompiler.\n"); + + /* Do architecture specific initialisation */ + init_dyn_rec(); + + /* FIXME: Find a better place for this */ + { /* Needed by execution */ + extern int do_stats; + do_stats = config.cpu.dependstats || config.cpu.superscalar || config.cpu.dependstats + || config.sim.history || config.sim.exe_log; + } + + printf("Recompile engine up and running\n"); +} + +/* Adds code to the opq for the instruction pointed to by addr */ +static void recompile_insn(struct op_queue *opq, oraddr_t addr, int delay_insn) +{ + unsigned int insn_index; + unsigned int pres_t[NUM_T_REGS]; /* Which temporary to preserve */ + orreg_t param[3]; + int i, j, k; + int param_t[3]; /* Which temporary the parameters reside in */ + int param_r[3]; /* is parameter a register */ + int param_num; + uint32_t insn; + int breakp; + struct insn_op_struct *opd; + + breakp = 0; + insn = eval_insn(addr, &breakp); + + /* FIXME: If a breakpoint is set at this location, insert exception code */ + if(breakp) { + fprintf(stderr, "FIXME: Insert breakpoint code\n"); + } + + insn_index = insn_decode(insn); + + /* Copy over the state of the temporaries to the next opq */ + memcpy(opq->reg_t_d, opq->reg_t, sizeof(opq->reg_t)); + + /* Check if we have an illegal instruction */ + if(insn_index == -1) { + gen_l_invalid(opq, NULL, NULL, delay_insn); + return; + } + + /* If we are recompileing an instruction that has a delay slot and is in the + * delay slot, ignore it. This is undefined behavour. */ + if(delay_insn && (or32_opcodes[insn_index].flags & OR32_IF_DELAY)) + return; + + /* figure out instruction operands */ + for(i = 0; i < NUM_T_REGS; i++) + pres_t[i] = 0; + + param_t[0] = T_NONE; + param_t[1] = T_NONE; + param_t[2] = T_NONE; + param_r[0] = 0; + param_r[1] = 0; + param_r[2] = 0; + param_num = 0; + + opd = op_start[insn_index]; + while(1) { + param[param_num] = eval_operand_val(insn, opd); + + if(opd->type & OPTYPE_REG) { + /* check which temporary the register is in, if any */ + for(i = 0; i < NUM_T_REGS; i++) { + if(opq->reg_t_d[i] == param[param_num]) { + param_t[param_num] = i; + pres_t[i] = 1; + } + } + } + + param_num++; + while(!(opd->type & OPTYPE_OP)) opd++; + if(opd->type & OPTYPE_LAST) + break; + opd++; + } + + /* Jump instructions are special since they have a delay slot and thus they + * need to control the exact operation sequence. Special case these here to + * avoid haveing loads of if(!(.& OR32_IF_DELAY)) below */ + if(or32_opcodes[insn_index].flags & OR32_IF_DELAY) { + /* Ship the jump-to register out (if it exists). It requires special + * handleing, which is done in gen_j_reg. */ + for(i = 0; i < NUM_T_REGS; i++) { + if(pres_t[i]) { + gen_op_move_gpr_t[i][opq->reg_t_d[i]](opq->prev, 1); + opq->reg_t_d[i] = 32; + opq->reg_t[i] = 32; + } + } + + /* FIXME: Do this in a more elegent way */ + if(!strncmp(or32_opcodes[insn_index].name, "l.jal", 5)) { + /* In the case of a l.jal instruction, make sure that LINK_REGNO is not in + * a temporary. The problem is that the l.jal(r) instruction stores the + * `return address' in LINK_REGNO. The temporaries are shiped out only + * after the delay slot instruction has executed and so it overwrittes the + * `return address'. */ + for(k = 0; k < NUM_T_REGS; k++) { + if(opq->reg_t_d[k] == LINK_REGNO) { + gen_op_move_gpr_t[k][LINK_REGNO](opq, 1); + opq->reg_t_d[k] = 32; + break; + } + } + } + + /* Jump instructions don't have a disposition */ + or32_opcodes[insn_index].exec(opq, param_t, param, delay_insn); + + /* Analysis is done by the individual jump instructions */ + /* Jump instructions don't touch runtime.sim.mem_cycles */ + /* Jump instructions run their own scheduler */ + return; + } + + /* Before an exception takes place, all registers must be stored. */ + if((or32_opcodes[insn_index].func_unit == it_exception)) { + if(opq->prev) { + ship_gprs_out_t(opq->prev, 1, opq->reg_t_d); + for(i = 0; i < NUM_T_REGS; i++) { + opq->reg_t_d[i] = 32; + opq->reg_t[i] = 32; + } + } + } + + opd = op_start[insn_index]; + + for(j = 0; j < param_num; j++, opd++) { + while(!(opd->type & OPTYPE_OP)) opd++; + if(!(opd->type & OPTYPE_REG)) + continue; + + /* Never, ever, move r0 into a temporary */ + if(!param[j]) + continue; + + /* Check if this register has been moved into a temporary in a previous + * operand */ + for(k = 0; k < NUM_T_REGS; k++) { + if(opq->reg_t_d[k] == param[j]) { + /* Yes, this register is already in a temporary */ + if(or32_opcodes[insn_index].func_unit != it_jump) { + pres_t[k] = 1; + param_t[j] = k; + } + break; + } + } + if(k != NUM_T_REGS) + continue; + + if(param_t[j] != T_NONE) + continue; + + /* Search for an unused temporary */ + k = find_unused_t(pres_t, opq->reg_t_d); + if(opq->reg_t_d[k] < 32) { + /* FIXME: Only ship the temporary out if it has been used as a destination + * register */ + gen_op_move_gpr_t[k][opq->reg_t_d[k]](opq->prev, 1); + opq->reg_t[k] = 32; + opq->reg_t_d[k] = 32; + } + pres_t[k] = 1; + opq->reg_t_d[k] = param[j]; + param_t[j] = k; + /* FIXME: Only generate code to move the register into a temporary if it + * is used as a source operand */ + gen_op_move_t_gpr[k][opq->reg_t_d[k]](opq, 0); + } + + /* To get the execution log correct for instructions like l.lwz r4,0(r4) the + * effective address needs to be calculated before the instruction is + * simulated */ + if(do_stats) { + /* Find any disposition in the instruction */ + opd = op_start[insn_index]; + for(j = 0; j < param_num; j++, opd++) { + while(!(opd->type & OPTYPE_OP)) opd++; + if(!(opd->type & OPTYPE_DIS)) + continue; + + if(!param[j + 1]) + gen_op_store_insn_ea(opq, 1, param[j]); + else + calc_insn_ea_table[param_t[j + 1]](opq, 1, param[j]); + } + } + + or32_opcodes[insn_index].exec(opq, param_t, param, delay_insn); + + if(or32_opcodes[insn_index].func_unit != it_exception) { + if(do_stats) + gen_op_analysis(opq, 1, insn_index, insn); + } + + /* The call to join_mem_cycles() could be put into the individual operations + * that emulate the load/store instructions, but then it would be added to + * the cycle counter before analysis() is called, which is not how the complex + * execution model does it. */ + if((or32_opcodes[insn_index].func_unit == it_load) || + (or32_opcodes[insn_index].func_unit == it_store)) + gen_op_join_mem_cycles(opq, 1); + + /* Delay slot instructions get a special scheduler, thus don't generate it + * here */ + if((or32_opcodes[insn_index].func_unit != it_exception) && !delay_insn) + gen_op_do_sched(opq, 1); +} + +/* Recompiles the page associated with *dyn */ +void recompile_page(struct dyn_page *dyn) +{ + unsigned int j; + struct op_queue *opq = cpu_state.opqs; + oraddr_t rec_addr = dyn->or_page; + oraddr_t rec_page = dyn->or_page; + void **loc; + + /* The start of the next page */ + rec_page += config.immu.pagesize; + + printf("Recompileing page %"PRIxADDR"\n", rec_addr); + fflush(stdout); + + /* Mark all temporaries as not containing a register */ + for(j = 0; j < NUM_T_REGS; j++) + opq->reg_t[j] = 32; /* Out-of-range registers */ + + dyn->delayr = -verify_memoryarea(rec_addr)->ops.delayr; + + opq->num_ops = 0; + opq->num_ops_param = 0; + + /* Insert code to check if the first instruction is exeucted in a delay slot*/ + gen_op_check_delay_slot(opq, 1, 0); + recompile_insn(opq, rec_addr, 1); + ship_gprs_out_t(opq, 1, opq->reg_t_d); + gen_op_do_sched_delay(opq, 1); + gen_op_clear_delay_insn(opq, 1); + gen_op_do_jump_delay(opq, 1); + gen_op_mark_loc(opq, 1); + + for(j = 0; j < NUM_T_REGS; j++) + opq->reg_t[j] = 32; /* Out-of-range registers */ + + for(; rec_addr < rec_page; rec_addr += 4, opq = opq->next) { + if(opq->prev) { + opq->num_ops = 0; + opq->num_ops_param = 0; + } + opq->jump_local = -1; + opq->not_jump_loc = -1; + + opq->insn_addr = rec_addr; + + /* Check if this location is cross referenced */ + if(opq->xref) { + /* If the current address is cross-referenced, the temporaries shall be + * in an undefined state, so we must assume that no registers reside in + * them */ + /* Ship out the current set of registers from the temporaries */ + if(opq->prev) + ship_gprs_out_t(opq->prev, 1, opq->reg_t); + + for(j = 0; j < NUM_T_REGS; j++) + opq->reg_t[j] = 32; + } + + recompile_insn(opq, rec_addr, 0); + + /* Store the state of the temporaries */ + memcpy(opq->next->reg_t, opq->reg_t_d, sizeof(opq->reg_t)); + } + + dyn->dirty = 0; + + /* Store the state of the temporaries */ + dyn->ts_bound[config.immu.pagesize >> 2] = dyn->ts_during[j]; + + /* Ship temporaries out to the corrisponding registers */ + ship_gprs_out_t(opq->prev, 1, opq->reg_t); + + opq->num_ops = 0; + opq->num_ops_param = 0; + opq->not_jump_loc = -1; + opq->jump_local = -1; + + /* Insert code to jump to the next page */ + gen_op_set_ts_current(opq, 1); + gen_op_do_jump(opq, 1); + + /* Generate the code */ + gen_code(cpu_state.opqs, dyn); + + /* Fix up the locations */ + for(loc = dyn->locs; loc < &dyn->locs[config.immu.pagesize / 4]; loc++) + *loc += (unsigned int)dyn->host_page; + + cpu_state.opqs->ops_param[0] += (unsigned int)dyn->host_page; + + /* Search for page-local jumps */ + opq = cpu_state.opqs; + for(j = 0; j < (config.immu.pagesize / 4); opq = opq->next, j++) { + if(opq->jump_local != -1) + opq->ops_param[opq->jump_local] = + (unsigned int)dyn->locs[opq->jump_local_loc >> 2]; + + if(opq->not_jump_loc != -1) + opq->ops_param[opq->not_jump_loc] = (unsigned int)dyn->locs[j + 1]; + + /* Store the state of the temporaries into dyn->ts_bound */ + dyn->ts_bound[j] = 0; + if(opq->reg_t[0] < 32) + dyn->ts_bound[j] = opq->reg_t[0]; + if(opq->reg_t[1] < 32) + dyn->ts_bound[j] |= opq->reg_t[1] << 5; + if(opq->reg_t[2] < 32) + dyn->ts_bound[j] |= opq->reg_t[2] << 10; + + dyn->ts_during[j] = 0; + if(opq->reg_t_d[0] < 32) + dyn->ts_during[j] = opq->reg_t_d[0]; + if(opq->reg_t_d[1] < 32) + dyn->ts_during[j] |= opq->reg_t_d[1] << 5; + if(opq->reg_t_d[2] < 32) + dyn->ts_during[j] |= opq->reg_t_d[2] << 10; + } + + /* Patch the relocations */ + patch_relocs(cpu_state.opqs, dyn->host_page); + + /* FIXME: Fix the issue below in a more elegent way */ + /* Since eval_insn is called to get the instruction, runtime.sim.mem_cycles is + * updated but the recompiler expectes it to start a 0, so reset it */ + runtime.sim.mem_cycles = 0; +} + +/* Returns non-zero if the jump is into this page, 0 otherwise */ +static int find_jump_loc(oraddr_t j_ea, struct op_queue *opq) +{ + int i; + + /* Mark the jump as non page local if the delay slot instruction is on the + * next page to the jump instruction. This should not be needed */ + if((IADDR_PAGE(j_ea) != IADDR_PAGE(opq->insn_addr)) || + (IADDR_PAGE(opq->insn_addr) != IADDR_PAGE(opq->insn_addr + 4))) + /* We can't do anything as the j_ea (as passed to find_jump_loc) is a + * VIRTUAL offset and the next physical page may not be the next VIRTUAL + * page */ + return 0; + + /* The jump is into the page currently undergoing dynamic recompilation */ + + /* If we haven't got to the location of the jump, everything is ok */ + if(j_ea > opq->insn_addr) { + /* Find the corissponding opq and mark it as cross referenced */ + for(i = (j_ea - opq->insn_addr) / 4; i; i--) + opq = opq->next; + opq->xref = 1; + return 1; + } + + /* Insert temporary -> register code before the jump ea and register -> + * temporary at the x-ref address */ + for(i = (opq->insn_addr - j_ea) / 4; i; i--) + opq = opq->prev; + + if(!opq->prev) + /* We're at the begining of a page, no need to do anything */ + return 1; + + /* Found location, insert code */ + + ship_gprs_out_t(opq->prev, 1, opq->reg_t); + + for(i = 0; i < NUM_T_REGS; i++) { + if(opq->reg_t[i] < 32) { + gen_op_move_t_gpr[i][opq->reg_t[i]](opq, 0); + opq->reg_t[i] = 32; + } + } + + opq->xref = 1; + + return 1; +} + +static void gen_j_imm(struct op_queue *opq, oraddr_t off) +{ + int jump_local; + int i; + int reg_t[NUM_T_REGS]; + + off <<= 2; + + jump_local = find_jump_loc(opq->insn_addr + off, opq); + + if(IADDR_PAGE(opq->insn_addr) != IADDR_PAGE(opq->insn_addr + 4)) { + gen_op_set_pc_delay_imm(opq, 1, off); + gen_op_do_sched(opq, 1); + return; + } + + gen_op_set_delay_insn(opq, 1); + gen_op_do_sched(opq, 1); + + /* Recompileing the delay slot instruction must see the temoraries being in + * the state after the jump/branch instruction not before */ + memcpy(reg_t, opq->reg_t, sizeof(reg_t)); + memcpy(opq->reg_t, opq->reg_t_d, sizeof(reg_t)); + + /* Generate the delay slot instruction */ + recompile_insn(opq, opq->insn_addr + 4, 1); + + memcpy(opq->reg_t, reg_t, sizeof(reg_t)); + + ship_gprs_out_t(opq, 1, opq->reg_t_d); + + gen_op_add_pc(opq, 1, (orreg_t)off - 8); + gen_op_clear_delay_insn(opq, 1); + gen_op_do_sched_delay(opq, 1); + + if(jump_local) { + gen_op_jmp_imm(opq, 1, 0); + opq->jump_local = opq->num_ops_param - 1; + opq->jump_local_loc = (opq->insn_addr + (orreg_t)off) & (config.immu.pagesize - 1); + } else + gen_op_do_jump(opq, 1); +} + +static const generic_gen_op set_pc_delay_gpr[32] = { + NULL, + gen_op_move_gpr1_pc_delay, + gen_op_move_gpr2_pc_delay, + gen_op_move_gpr3_pc_delay, + gen_op_move_gpr4_pc_delay, + gen_op_move_gpr5_pc_delay, + gen_op_move_gpr6_pc_delay, + gen_op_move_gpr7_pc_delay, + gen_op_move_gpr8_pc_delay, + gen_op_move_gpr9_pc_delay, + gen_op_move_gpr10_pc_delay, + gen_op_move_gpr11_pc_delay, + gen_op_move_gpr12_pc_delay, + gen_op_move_gpr13_pc_delay, + gen_op_move_gpr14_pc_delay, + gen_op_move_gpr15_pc_delay, + gen_op_move_gpr16_pc_delay, + gen_op_move_gpr17_pc_delay, + gen_op_move_gpr18_pc_delay, + gen_op_move_gpr19_pc_delay, + gen_op_move_gpr20_pc_delay, + gen_op_move_gpr21_pc_delay, + gen_op_move_gpr22_pc_delay, + gen_op_move_gpr23_pc_delay, + gen_op_move_gpr24_pc_delay, + gen_op_move_gpr25_pc_delay, + gen_op_move_gpr26_pc_delay, + gen_op_move_gpr27_pc_delay, + gen_op_move_gpr28_pc_delay, + gen_op_move_gpr29_pc_delay, + gen_op_move_gpr30_pc_delay, + gen_op_move_gpr31_pc_delay }; + +static void gen_j_reg(struct op_queue *opq, unsigned int gpr, int insn_index, + uint32_t insn) +{ + int i; + int reg_t[NUM_T_REGS]; + + if(do_stats) + gen_op_analysis(opq, 1, insn_index, insn); + + if(!gpr) + gen_op_clear_pc_delay(opq, 1); + else + set_pc_delay_gpr[gpr](opq, 1); + + gen_op_do_sched(opq, 1); + + /* Recompileing the delay slot instruction must see the temoraries being in + * the state after the jump/branch instruction not before */ + memcpy(reg_t, opq->reg_t, sizeof(reg_t)); + memcpy(opq->reg_t, opq->reg_t_d, sizeof(reg_t)); + + /* Generate the delay slot instruction */ + gen_op_set_delay_insn(opq, 1); + recompile_insn(opq, opq->insn_addr + 4, 1); + + memcpy(opq->reg_t, reg_t, sizeof(reg_t)); + + ship_gprs_out_t(opq, 1, opq->reg_t_d); + + gen_op_set_pc_pc_delay(opq, 1); + gen_op_clear_delay_insn(opq, 1); + gen_op_do_sched_delay(opq, 1); + + gen_op_do_jump_delay(opq, 1); +} + +/*------------------------------[ Operation generation for an instruction ]---*/ +/* FIXME: Flag setting is not done in any instruction */ +/* FIXME: Since r0 is not moved into a temporary, check all arguments below! */ + +static const generic_gen_op clear_t[NUM_T_REGS] = + { gen_op_clear_t0, gen_op_clear_t1, gen_op_clear_t2 }; + +static const generic_gen_op move_t_t[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { NULL, gen_op_move_t0_t1, gen_op_move_t0_t2 }, +/* param0 -> t1 */ { gen_op_move_t1_t0, NULL, gen_op_move_t1_t2 }, +/* param0 -> t2 */ { gen_op_move_t2_t0, gen_op_move_t2_t1, NULL } }; + +static const imm_gen_op mov_t_imm[NUM_T_REGS] = + { gen_op_t0_imm, gen_op_t1_imm, gen_op_t2_imm }; + +static const imm_gen_op l_add_imm_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_add_imm_t0_t0, gen_op_add_imm_t0_t1, gen_op_add_imm_t0_t2 }, +/* param0 -> t1 */ { gen_op_add_imm_t1_t0, gen_op_add_imm_t1_t1, gen_op_add_imm_t1_t2 }, +/* param0 -> t2 */ { gen_op_add_imm_t2_t0, gen_op_add_imm_t2_t1, gen_op_add_imm_t2_t2 } }; + +static const generic_gen_op l_add_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { +/* param0 -> t0, param1 -> t0 */ { gen_op_add_t0_t0_t0, gen_op_add_t0_t0_t1, gen_op_add_t0_t0_t2 }, +/* param0 -> t0, param1 -> t1 */ { gen_op_add_t0_t1_t0, gen_op_add_t0_t1_t1, gen_op_add_t0_t1_t2 }, +/* param0 -> t0, param1 -> t2 */ { gen_op_add_t0_t2_t0, gen_op_add_t0_t2_t1, gen_op_add_t0_t2_t2 } }, +/* param0 -> t1 */ { +/* param0 -> t1, param1 -> t0 */ { gen_op_add_t1_t0_t0, gen_op_add_t1_t0_t1, gen_op_add_t1_t0_t2 }, +/* param0 -> t1, param1 -> t1 */ { gen_op_add_t1_t1_t0, gen_op_add_t1_t1_t1, gen_op_add_t1_t1_t2 }, +/* param0 -> t1, param1 -> t2 */ { gen_op_add_t1_t2_t0, gen_op_add_t1_t2_t1, gen_op_add_t1_t2_t2 } }, +/* param0 -> t2 */ { +/* param0 -> t2, param1 -> t0 */ { gen_op_add_t2_t0_t0, gen_op_add_t2_t0_t1, gen_op_add_t2_t0_t2 }, +/* param0 -> t2, param1 -> t1 */ { gen_op_add_t2_t1_t0, gen_op_add_t2_t1_t1, gen_op_add_t2_t1_t2 }, +/* param0 -> t2, param1 -> t2 */ { gen_op_add_t2_t2_t0, gen_op_add_t2_t2_t1, gen_op_add_t2_t2_t2 } } }; + +void gen_l_add(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) + /* Screw this, the operation shall do nothing */ + return; + + if(!param[1] && !param[2]) { + /* Just clear param_t[0] */ + clear_t[param_t[0]](opq, 1); + return; + } + + if(!param[2]) { + if(param[0] != param[1]) + /* This just moves a register */ + move_t_t[param_t[0]][param_t[1]](opq, 1); + return; + } + + if(!param[1]) { + /* Check if we are moveing an immediate */ + if(param_t[2] == T_NONE) { + /* Yep, an immediate */ + mov_t_imm[param_t[0]](opq, 1, param[2]); + return; + } + /* Just another move */ + if(param[0] != param[2]) + move_t_t[param_t[0]][param_t[2]](opq, 1); + return; + } + + /* Ok, This _IS_ an add... */ + if(param_t[2] == T_NONE) + /* immediate */ + l_add_imm_t_table[param_t[0]][param_t[1]](opq, 1, param[2]); + else + l_add_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); +} + +static const generic_gen_op l_addc_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { +/* param0 -> t0, param1 -> t0 */ { gen_op_addc_t0_t0_t0, gen_op_addc_t0_t0_t1, gen_op_addc_t0_t0_t2 }, +/* param0 -> t0, param1 -> t1 */ { gen_op_addc_t0_t1_t0, gen_op_addc_t0_t1_t1, gen_op_addc_t0_t1_t2 }, +/* param0 -> t0, param1 -> t2 */ { gen_op_addc_t0_t2_t0, gen_op_addc_t0_t2_t1, gen_op_addc_t0_t2_t2 } }, +/* param0 -> t1 */ { +/* param0 -> t1, param1 -> t0 */ { gen_op_addc_t1_t0_t0, gen_op_addc_t1_t0_t1, gen_op_addc_t1_t0_t2 }, +/* param0 -> t1, param1 -> t1 */ { gen_op_addc_t1_t1_t0, gen_op_addc_t1_t1_t1, gen_op_addc_t1_t1_t2 }, +/* param0 -> t1, param1 -> t2 */ { gen_op_addc_t1_t2_t0, gen_op_addc_t1_t2_t1, gen_op_addc_t1_t2_t2 } }, +/* param0 -> t2 */ { +/* param0 -> t2, param1 -> t0 */ { gen_op_addc_t2_t0_t0, gen_op_addc_t2_t0_t1, gen_op_addc_t2_t0_t2 }, +/* param0 -> t2, param1 -> t1 */ { gen_op_addc_t2_t1_t0, gen_op_addc_t2_t1_t1, gen_op_addc_t2_t1_t2 }, +/* param0 -> t2, param1 -> t2 */ { gen_op_addc_t2_t2_t0, gen_op_addc_t2_t2_t1, gen_op_addc_t2_t2_t2 } } }; + +void gen_l_addc(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) + /* Screw this, the operation shall do nothing */ + return; + + /* FIXME: More optimisations !! (...and immediate...) */ + l_addc_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); +} + +static const imm_gen_op l_and_imm_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_and_imm_t0_t0, gen_op_and_imm_t0_t1, gen_op_and_imm_t0_t2 }, +/* param0 -> t1 */ { gen_op_and_imm_t1_t0, gen_op_and_imm_t1_t1, gen_op_and_imm_t1_t2 }, +/* param0 -> t2 */ { gen_op_and_imm_t2_t0, gen_op_and_imm_t2_t1, gen_op_and_imm_t2_t2 } }; + +static const generic_gen_op l_and_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { +/* param0 -> t0, param1 -> t0 */ { NULL, gen_op_and_t0_t0_t1, gen_op_and_t0_t0_t2 }, +/* param0 -> t0, param1 -> t1 */ { gen_op_and_t0_t1_t0, gen_op_and_t0_t1_t1, gen_op_and_t0_t1_t2 }, +/* param0 -> t0, param1 -> t2 */ { gen_op_and_t0_t2_t0, gen_op_and_t0_t2_t1, gen_op_and_t0_t2_t2 } }, +/* param0 -> t1 */ { +/* param0 -> t1, param1 -> t0 */ { gen_op_and_t1_t0_t0, gen_op_and_t1_t0_t1, gen_op_and_t1_t0_t2 }, +/* param0 -> t1, param1 -> t1 */ { gen_op_and_t1_t1_t0, NULL, gen_op_and_t1_t1_t2 }, +/* param0 -> t1, param1 -> t2 */ { gen_op_and_t1_t2_t0, gen_op_and_t1_t2_t1, gen_op_and_t1_t2_t2 } }, +/* param0 -> t2 */ { +/* param0 -> t2, param1 -> t0 */ { gen_op_and_t2_t0_t0, gen_op_and_t2_t0_t1, gen_op_and_t2_t0_t2 }, +/* param0 -> t2, param1 -> t1 */ { gen_op_and_t2_t1_t0, gen_op_and_t2_t1_t1, gen_op_and_t2_t1_t2 }, +/* param0 -> t2, param1 -> t2 */ { gen_op_and_t2_t2_t0, gen_op_and_t2_t2_t1, NULL } } }; + +void gen_l_and(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) + /* Screw this, the operation shall do nothing */ + return; + + if(!param[1] || !param[2]) { + /* Just clear param_t[0] */ + clear_t[param_t[0]](opq, 1); + return; + } + + if((param[0] == param[1] == param[2]) && (param_t[2] != T_NONE)) + return; + + if(param_t[2] == T_NONE) + l_and_imm_t_table[param_t[0]][param_t[1]](opq, 1, param[2]); + else + l_and_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); +} + +void gen_l_bf(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + int i; + if(do_stats) + gen_op_analysis(opq, 1, 3, 0x10000000 | (param[0] & 0x03ffffff)); + + /* The temporaries are expected to be shiped out after the execution of the + * branch instruction wether it branched or not */ + if(opq->prev) { + ship_gprs_out_t(opq->prev, 1, opq->reg_t); + for(i = 0; i < NUM_T_REGS; i++) { + opq->reg_t[i] = 32; + opq->reg_t_d[i] = 32; + } + } + + if(IADDR_PAGE(opq->insn_addr) != IADDR_PAGE(opq->insn_addr + 4)) { + gen_op_check_flag_delay(opq, 1, param[0] << 2); + gen_op_do_sched(opq, 1); + opq->not_jump_loc = -1; + return; + } + + gen_op_check_flag(opq, 1, 0); + opq->not_jump_loc = opq->num_ops_param - 1; + + gen_j_imm(opq, param[0]); +} + +void gen_l_bnf(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + int i; + if(do_stats) + gen_op_analysis(opq, 1, 2, 0x0c000000 | (param[0] & 0x03ffffff)); + + /* The temporaries are expected to be shiped out after the execution of the + * branch instruction wether it branched or not */ + if(opq->prev) { + ship_gprs_out_t(opq->prev, 1, opq->reg_t); + for(i = 0; i < NUM_T_REGS; i++) { + opq->reg_t[i] = 32; + opq->reg_t_d[i] = 32; + } + } + + if(IADDR_PAGE(opq->insn_addr) != IADDR_PAGE(opq->insn_addr + 4)) { + gen_op_check_not_flag_delay(opq, 1, param[0] << 2); + gen_op_do_sched(opq, 1); + opq->not_jump_loc = -1; + return; + } + + gen_op_check_not_flag(opq, 1, 0); + opq->not_jump_loc = opq->num_ops_param - 1; + + gen_j_imm(opq, param[0]); + + /* The temporaries don't get shiped out if the branch is not taken */ + memcpy(opq->next->reg_t, opq->reg_t, sizeof(opq->reg_t)); +} + +static const generic_gen_op l_cmov_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { +/* param0 -> t0, param1 -> t0 */ { NULL, gen_op_cmov_t0_t0_t1, gen_op_cmov_t0_t0_t2 }, +/* param0 -> t0, param1 -> t1 */ { gen_op_cmov_t0_t1_t0, NULL, gen_op_cmov_t0_t1_t2 }, +/* param0 -> t0, param1 -> t2 */ { gen_op_cmov_t0_t2_t0, gen_op_cmov_t0_t2_t1, NULL } }, +/* param0 -> t1 */ { +/* param0 -> t1, param1 -> t0 */ { NULL, gen_op_cmov_t1_t0_t1, gen_op_cmov_t1_t0_t2 }, +/* param0 -> t1, param1 -> t1 */ { gen_op_cmov_t1_t1_t0, NULL, gen_op_cmov_t1_t1_t2 }, +/* param0 -> t1, param1 -> t2 */ { gen_op_cmov_t1_t2_t0, gen_op_cmov_t1_t2_t1, NULL } }, +/* param0 -> t2 */ { +/* param0 -> t2, param1 -> t0 */ { NULL, gen_op_cmov_t2_t0_t1, gen_op_cmov_t2_t0_t2 }, +/* param0 -> t2, param1 -> t1 */ { gen_op_cmov_t2_t1_t0, NULL, gen_op_cmov_t2_t1_t2 }, +/* param0 -> t2, param1 -> t2 */ { gen_op_cmov_t2_t2_t0, gen_op_cmov_t2_t2_t1, NULL } } }; + +/* FIXME: Check if either opperand 1 or 2 is r0 */ +void gen_l_cmov(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) + return; + + if(!param[1] && !param[2]) { + clear_t[param_t[0]](opq, 1); + return; + } + + if(param[1] == param[2]) { + move_t_t[param_t[0]][param_t[1]](opq, 1); + return; + } + + if((param[1] == param[2]) && (param[0] == param[1])) + return; + + l_cmov_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); +} + +void gen_l_cust1(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ +} + +void gen_l_cust2(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ +} + +void gen_l_cust3(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ +} + +void gen_l_cust4(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ +} + +void gen_l_cust5(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ +} + +void gen_l_cust6(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ +} + +void gen_l_cust7(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ +} + +void gen_l_cust8(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ +} + +/* FIXME: All registers need to be stored before the div instructions as they + * have the potenticial to cause an exception */ + +static const generic_gen_op check_null_excpt[NUM_T_REGS] = + { gen_op_check_null_except_t0, gen_op_check_null_except_t1, gen_op_check_null_except_t2 }; + +static const generic_gen_op check_null_excpt_delay[NUM_T_REGS] = { + gen_op_check_null_except_t0_delay, + gen_op_check_null_except_t1_delay, + gen_op_check_null_except_t2_delay }; + +static const generic_gen_op l_div_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { +/* param0 -> t0, param1 -> t0 */ { gen_op_div_t0_t0_t0, gen_op_div_t0_t0_t1, gen_op_div_t0_t0_t2 }, +/* param0 -> t0, param1 -> t1 */ { gen_op_div_t0_t1_t0, gen_op_div_t0_t1_t1, gen_op_div_t0_t1_t2 }, +/* param0 -> t0, param1 -> t2 */ { gen_op_div_t0_t2_t0, gen_op_div_t0_t2_t1, gen_op_div_t0_t2_t2 } }, +/* param0 -> t1 */ { +/* param0 -> t1, param1 -> t0 */ { gen_op_div_t1_t0_t0, gen_op_div_t1_t0_t1, gen_op_div_t1_t0_t2 }, +/* param0 -> t1, param1 -> t1 */ { gen_op_div_t1_t1_t0, gen_op_div_t1_t1_t1, gen_op_div_t1_t1_t2 }, +/* param0 -> t1, param1 -> t2 */ { gen_op_div_t1_t2_t0, gen_op_div_t1_t2_t1, gen_op_div_t1_t2_t2 } }, +/* param0 -> t2 */ { +/* param0 -> t2, param1 -> t0 */ { gen_op_div_t2_t0_t0, gen_op_div_t2_t0_t1, gen_op_div_t2_t0_t2 }, +/* param0 -> t2, param1 -> t1 */ { gen_op_div_t2_t1_t0, gen_op_div_t2_t1_t1, gen_op_div_t2_t1_t2 }, +/* param0 -> t2, param1 -> t2 */ { gen_op_div_t2_t2_t0, gen_op_div_t2_t2_t1, gen_op_div_t2_t2_t2 } } }; + +void gen_l_div(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[2]) { + /* There is no option. This _will_ cause an illeagal exception */ + if(!delay_slot) + gen_op_illegal(opq, 1); + else + gen_op_illegal(opq, 1); + return; + } + + if(!delay_slot) + check_null_excpt[param_t[2]](opq, 1); + else + check_null_excpt_delay[param_t[2]](opq, 1); + + if(!param[0]) + return; + + if(!param[1]) { + /* Clear param_t[0] */ + clear_t[param_t[0]](opq, 1); + return; + } + + l_div_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); +} + +static const generic_gen_op l_divu_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { +/* param0 -> t0, param1 -> t0 */ { gen_op_divu_t0_t0_t0, gen_op_divu_t0_t0_t1, gen_op_divu_t0_t0_t2 }, +/* param0 -> t0, param1 -> t1 */ { gen_op_divu_t0_t1_t0, gen_op_divu_t0_t1_t1, gen_op_divu_t0_t1_t2 }, +/* param0 -> t0, param1 -> t2 */ { gen_op_divu_t0_t2_t0, gen_op_divu_t0_t2_t1, gen_op_divu_t0_t2_t2 } }, +/* param0 -> t1 */ { +/* param0 -> t1, param1 -> t0 */ { gen_op_divu_t1_t0_t0, gen_op_divu_t1_t0_t1, gen_op_divu_t1_t0_t2 }, +/* param0 -> t1, param1 -> t1 */ { gen_op_divu_t1_t1_t0, gen_op_divu_t1_t1_t1, gen_op_divu_t1_t1_t2 }, +/* param0 -> t1, param1 -> t2 */ { gen_op_divu_t1_t2_t0, gen_op_divu_t1_t2_t1, gen_op_divu_t1_t2_t2 } }, +/* param0 -> t2 */ { +/* param0 -> t2, param1 -> t0 */ { gen_op_divu_t2_t0_t0, gen_op_divu_t2_t0_t1, gen_op_divu_t2_t0_t2 }, +/* param0 -> t2, param1 -> t1 */ { gen_op_divu_t2_t1_t0, gen_op_divu_t2_t1_t1, gen_op_divu_t2_t1_t2 }, +/* param0 -> t2, param1 -> t2 */ { gen_op_divu_t2_t2_t0, gen_op_divu_t2_t2_t1, gen_op_divu_t2_t2_t2 } } }; + +void gen_l_divu(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[2]) { + /* There is no option. This _will_ cause an illeagal exception */ + if(!delay_slot) + gen_op_illegal(opq, 1); + else + gen_op_illegal(opq, 1); + return; + } + + if(!delay_slot) + check_null_excpt[param_t[2]](opq, 1); + else + check_null_excpt_delay[param_t[2]](opq, 1); + + if(!param[0]) + return; + + if(!param[1]) { + /* Clear param_t[0] */ + clear_t[param_t[0]](opq, 1); + return; + } + + l_divu_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); +} + +static const generic_gen_op l_extbs_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_extbs_t0_t0, gen_op_extbs_t0_t1, gen_op_extbs_t0_t2 }, +/* param0 -> t1 */ { gen_op_extbs_t1_t0, gen_op_extbs_t1_t1, gen_op_extbs_t1_t2 }, +/* param0 -> t2 */ { gen_op_extbs_t2_t0, gen_op_extbs_t2_t1, gen_op_extbs_t2_t2 } }; + +void gen_l_extbs(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) + return; + + if(!param[1]) { + clear_t[param_t[0]](opq, 1); + return; + } + + l_extbs_t_table[param_t[0]][param_t[1]](opq, 1); +} + +static const generic_gen_op l_extbz_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_extbz_t0_t0, gen_op_extbz_t0_t1, gen_op_extbz_t0_t2 }, +/* param0 -> t1 */ { gen_op_extbz_t1_t0, gen_op_extbz_t1_t1, gen_op_extbz_t1_t2 }, +/* param0 -> t2 */ { gen_op_extbz_t2_t0, gen_op_extbz_t2_t1, gen_op_extbz_t2_t2 } }; + +void gen_l_extbz(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) + return; + + if(!param[1]) { + clear_t[param_t[0]](opq, 1); + return; + } + + l_extbz_t_table[param_t[0]][param_t[1]](opq, 1); +} + +static const generic_gen_op l_exths_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_exths_t0_t0, gen_op_exths_t0_t1, gen_op_exths_t0_t2 }, +/* param0 -> t1 */ { gen_op_exths_t1_t0, gen_op_exths_t1_t1, gen_op_exths_t1_t2 }, +/* param0 -> t2 */ { gen_op_exths_t2_t0, gen_op_exths_t2_t1, gen_op_exths_t2_t2 } }; + +void gen_l_exths(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) + return; + + if(!param[1]) { + clear_t[param_t[0]](opq, 1); + return; + } + + l_exths_t_table[param_t[0]][param_t[1]](opq, 1); +} + +static const generic_gen_op l_exthz_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_exthz_t0_t0, gen_op_exthz_t0_t1, gen_op_exthz_t0_t2 }, +/* param0 -> t1 */ { gen_op_exthz_t1_t0, gen_op_exthz_t1_t1, gen_op_exthz_t1_t2 }, +/* param0 -> t2 */ { gen_op_exthz_t2_t0, gen_op_exthz_t2_t1, gen_op_exthz_t2_t2 } }; + +void gen_l_exthz(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) + return; + + if(!param[1]) { + clear_t[param_t[0]](opq, 1); + return; + } + + l_exthz_t_table[param_t[0]][param_t[1]](opq, 1); +} + +void gen_l_extws(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) + return; + + if(!param[1]) { + clear_t[param_t[0]](opq, 1); + return; + } + + if(param[0] == param[1]) + return; + + /* In the 32-bit architechture this instruction reduces to a move */ + move_t_t[param_t[0]][param_t[1]](opq, 1); +} + +void gen_l_extwz(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) + return; + + if(!param[1]) { + clear_t[param_t[0]](opq, 1); + return; + } + + if(param[0] == param[1]) + return; + + /* In the 32-bit architechture this instruction reduces to a move */ + move_t_t[param_t[0]][param_t[1]](opq, 1); +} + +static const generic_gen_op l_ff1_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_ff1_t0_t0, gen_op_ff1_t0_t1, gen_op_ff1_t0_t2 }, +/* param0 -> t1 */ { gen_op_ff1_t1_t0, gen_op_ff1_t1_t1, gen_op_ff1_t1_t2 }, +/* param0 -> t2 */ { gen_op_ff1_t2_t0, gen_op_ff1_t2_t1, gen_op_ff1_t2_t2 } }; + +void gen_l_ff1(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) + return; + + if(!param[1]) { + clear_t[param_t[0]](opq, 1); + return; + } + + l_ff1_t_table[param_t[0]][param_t[1]](opq, 1); +} + +void gen_l_j(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(do_stats) + gen_op_analysis(opq, 1, 0, param[0] & 0x03ffffff); + + gen_j_imm(opq, param[0]); +} + +void gen_l_jal(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + /* Store the return address */ + gen_op_store_link_addr_gpr(opq, 1); + + if(do_stats) + gen_op_analysis(opq, 1, 1, 0x04000000 | (param[0] & 0x03ffffff)); + + gen_j_imm(opq, param[0]); +} + +void gen_l_jr(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + gen_j_reg(opq, param[0], 104, 0x14000000 | (param[0] << 11)); +} + +void gen_l_jalr(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + /* Store the return address */ + gen_op_store_link_addr_gpr(opq, 1); + + gen_j_reg(opq, param[0], 105, 0x18000000 | (param[0] << 11)); +} + +/* FIXME: Optimise all load instruction when the disposition == 0 */ + +static const imm_gen_op l_lbs_imm_t_table[NUM_T_REGS] = + { gen_op_lbs_imm_t0, gen_op_lbs_imm_t1, gen_op_lbs_imm_t2 }; + +static const imm_gen_op l_lbs_t_table[3][3] = { +/* param0 -> t0 */ { gen_op_lbs_t0_t0, gen_op_lbs_t0_t1, gen_op_lbs_t0_t2 }, +/* param0 -> t1 */ { gen_op_lbs_t1_t0, gen_op_lbs_t1_t1, gen_op_lbs_t1_t2 }, +/* param0 -> t2 */ { gen_op_lbs_t2_t0, gen_op_lbs_t2_t1, gen_op_lbs_t2_t2 } }; + +void gen_l_lbs(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) { + /* FIXME: This will work, but the statistics need to be updated... */ + return; + } + + if(!param[2]) { + /* Load the data from the immediate */ + l_lbs_imm_t_table[param_t[0]](opq, 1, param[1]); + return; + } + + l_lbs_t_table[param_t[0]][param_t[2]](opq, 1, param[1]); +} + +static const imm_gen_op l_lbz_imm_t_table[NUM_T_REGS] = + { gen_op_lbz_imm_t0, gen_op_lbz_imm_t1, gen_op_lbz_imm_t2 }; + +static const imm_gen_op l_lbz_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_lbz_t0_t0, gen_op_lbz_t0_t1, gen_op_lbz_t0_t2 }, +/* param0 -> t1 */ { gen_op_lbz_t1_t0, gen_op_lbz_t1_t1, gen_op_lbz_t1_t2 }, +/* param0 -> t2 */ { gen_op_lbz_t2_t0, gen_op_lbz_t2_t1, gen_op_lbz_t2_t2 } }; + +void gen_l_lbz(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) { + /* FIXME: This will work, but the statistics need to be updated... */ + return; + } + + if(!param[2]) { + /* Load the data from the immediate */ + l_lbz_imm_t_table[param_t[0]](opq, 1, param[1]); + return; + } + + l_lbz_t_table[param_t[0]][param_t[2]](opq, 1, param[1]); +} + +static const imm_gen_op l_lhs_imm_t_table[NUM_T_REGS] = + { gen_op_lhs_imm_t0, gen_op_lhs_imm_t1, gen_op_lhs_imm_t2 }; + +static const imm_gen_op l_lhs_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_lhs_t0_t0, gen_op_lhs_t0_t1, gen_op_lhs_t0_t2 }, +/* param0 -> t1 */ { gen_op_lhs_t1_t0, gen_op_lhs_t1_t1, gen_op_lhs_t1_t2 }, +/* param0 -> t2 */ { gen_op_lhs_t2_t0, gen_op_lhs_t2_t1, gen_op_lhs_t2_t2 } }; + +void gen_l_lhs(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) { + /* FIXME: This will work, but the statistics need to be updated... */ + return; + } + + if(!param[2]) { + /* Load the data from the immediate */ + l_lhs_imm_t_table[param_t[0]](opq, 1, param[1]); + return; + } + + l_lhs_t_table[param_t[0]][param_t[2]](opq, 1, param[1]); +} + +static const imm_gen_op l_lhz_imm_t_table[NUM_T_REGS] = + { gen_op_lhz_imm_t0, gen_op_lhz_imm_t1, gen_op_lhz_imm_t2 }; + +static const imm_gen_op l_lhz_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_lhz_t0_t0, gen_op_lhz_t0_t1, gen_op_lhz_t0_t2 }, +/* param0 -> t1 */ { gen_op_lhz_t1_t0, gen_op_lhz_t1_t1, gen_op_lhz_t1_t2 }, +/* param0 -> t2 */ { gen_op_lhz_t2_t0, gen_op_lhz_t2_t1, gen_op_lhz_t2_t2 } }; + +void gen_l_lhz(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) { + /* FIXME: This will work, but the statistics need to be updated... */ + return; + } + + if(!param[2]) { + /* Load the data from the immediate */ + l_lhz_imm_t_table[param_t[0]](opq, 1, param[1]); + return; + } + + l_lhz_t_table[param_t[0]][param_t[2]](opq, 1, param[1]); +} + +static const imm_gen_op l_lws_imm_t_table[NUM_T_REGS] = + { gen_op_lws_imm_t0, gen_op_lws_imm_t1, gen_op_lws_imm_t2 }; + +static const imm_gen_op l_lws_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_lws_t0_t0, gen_op_lws_t0_t1, gen_op_lws_t0_t2 }, +/* param0 -> t1 */ { gen_op_lws_t1_t0, gen_op_lws_t1_t1, gen_op_lws_t1_t2 }, +/* param0 -> t2 */ { gen_op_lws_t2_t0, gen_op_lws_t2_t1, gen_op_lws_t2_t2 } }; + +void gen_l_lws(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) { + /* FIXME: This will work, but the statistics need to be updated... */ + return; + } + + if(!param[2]) { + /* Load the data from the immediate */ + l_lws_imm_t_table[param_t[0]](opq, 1, param[1]); + return; + } + + l_lws_t_table[param_t[0]][param_t[2]](opq, 1, param[1]); +} + +static const imm_gen_op l_lwz_imm_t_table[NUM_T_REGS] = + { gen_op_lwz_imm_t0, gen_op_lwz_imm_t1, gen_op_lwz_imm_t2 }; + +static const imm_gen_op l_lwz_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_lwz_t0_t0, gen_op_lwz_t0_t1, gen_op_lwz_t0_t2 }, +/* param0 -> t1 */ { gen_op_lwz_t1_t0, gen_op_lwz_t1_t1, gen_op_lwz_t1_t2 }, +/* param0 -> t2 */ { gen_op_lwz_t2_t0, gen_op_lwz_t2_t1, gen_op_lwz_t2_t2 } }; + +void gen_l_lwz(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) { + /* FIXME: This will work, but the statistics need to be updated... */ + return; + } + + if(!param[2]) { + /* Load the data from the immediate */ + l_lwz_imm_t_table[param_t[0]](opq, 1, param[1]); + return; + } + + l_lwz_t_table[param_t[0]][param_t[2]](opq, 1, param[1]); +} + +static const imm_gen_op l_mac_imm_t_table[NUM_T_REGS] = + { gen_op_mac_imm_t0, gen_op_mac_imm_t1, gen_op_mac_imm_t2 }; + +static const generic_gen_op l_mac_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_mac_t0_t0, gen_op_mac_t0_t1, gen_op_mac_t0_t2 }, +/* param0 -> t1 */ { gen_op_mac_t0_t1, gen_op_mac_t1_t1, gen_op_mac_t1_t2 }, +/* param0 -> t2 */ { gen_op_mac_t0_t2, gen_op_mac_t1_t2, gen_op_mac_t2_t2 } }; + +void gen_l_mac(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0] || !param[1]) + return; + + if(param_t[1] == T_NONE) + l_mac_imm_t_table[param_t[0]](opq, 1, param[1]); + else + l_mac_t_table[param_t[0]][param_t[1]](opq, 1); +} + +static const generic_gen_op l_macrc_t_table[NUM_T_REGS] = + { gen_op_macrc_t0, gen_op_macrc_t1, gen_op_macrc_t2 }; + +void gen_l_macrc(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) { + gen_op_macc(opq, 1); + return; + } + + l_macrc_t_table[param_t[0]](opq, 1); +} + +static const imm_gen_op l_mfspr_imm_t_table[NUM_T_REGS] = + { gen_op_mfspr_t0_imm, gen_op_mfspr_t1_imm, gen_op_mfspr_t2_imm }; + +static const imm_gen_op l_mfspr_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_mfspr_t0_t0, gen_op_mfspr_t0_t1, gen_op_mfspr_t0_t2 }, +/* param0 -> t1 */ { gen_op_mfspr_t1_t0, gen_op_mfspr_t1_t1, gen_op_mfspr_t1_t2 }, +/* param0 -> t2 */ { gen_op_mfspr_t2_t0, gen_op_mfspr_t2_t1, gen_op_mfspr_t2_t2 } }; + +void gen_l_mfspr(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) + return; + + if(!param[1]) { + l_mfspr_imm_t_table[param_t[0]](opq, 1, param[2]); + return; + } + + l_mfspr_t_table[param_t[0]][param_t[1]](opq, 1, param[2]); +} + +void gen_l_movhi(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) + return; + + if(!param[1]) { + clear_t[param_t[0]](opq, 1); + return; + } + + mov_t_imm[param_t[0]](opq, 1, param[1] << 16); +} + +static const generic_gen_op l_msb_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_msb_t0_t0, gen_op_msb_t0_t1, gen_op_msb_t0_t2 }, +/* param0 -> t1 */ { gen_op_msb_t0_t1, gen_op_msb_t1_t1, gen_op_msb_t1_t2 }, +/* param0 -> t2 */ { gen_op_msb_t0_t2, gen_op_msb_t1_t2, gen_op_msb_t2_t2 } }; + +void gen_l_msb(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0] || !param[1]) + return; + + l_msb_t_table[param_t[0]][param_t[1]](opq, 1); +} + +static const imm_gen_op l_mtspr_clear_t_table[NUM_T_REGS] = + { gen_op_mtspr_t0_clear, gen_op_mtspr_t1_clear, gen_op_mtspr_t2_clear }; + +static const imm_gen_op l_mtspr_imm_t_table[NUM_T_REGS] = + { gen_op_mtspr_imm_t0, gen_op_mtspr_imm_t1, gen_op_mtspr_imm_t2 }; + +static const imm_gen_op l_mtspr_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_mtspr_t0_t0, gen_op_mtspr_t0_t1, gen_op_mtspr_t0_t2 }, +/* param0 -> t1 */ { gen_op_mtspr_t1_t0, gen_op_mtspr_t1_t1, gen_op_mtspr_t1_t2 }, +/* param0 -> t2 */ { gen_op_mtspr_t2_t0, gen_op_mtspr_t2_t1, gen_op_mtspr_t2_t2 } }; + +void gen_l_mtspr(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) { + if(!param[1]) { + /* Clear the immediate SPR */ + gen_op_mtspr_imm_clear(opq, 1, param[2]); + return; + } + l_mtspr_imm_t_table[param_t[1]](opq, 1, param[2]); + return; + } + + if(!param[1]) { + l_mtspr_clear_t_table[param_t[0]](opq, 1, param[2]); + return; + } + + l_mtspr_t_table[param_t[0]][param_t[1]](opq, 1, param[2]); +} + +static const imm_gen_op l_mul_imm_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_mul_imm_t0_t0, gen_op_mul_imm_t0_t1, gen_op_mul_imm_t0_t2 }, +/* param0 -> t1 */ { gen_op_mul_imm_t1_t0, gen_op_mul_imm_t1_t1, gen_op_mul_imm_t1_t2 }, +/* param0 -> t2 */ { gen_op_mul_imm_t2_t0, gen_op_mul_imm_t2_t1, gen_op_mul_imm_t2_t2 } }; + +static const generic_gen_op l_mul_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { +/* param0 -> t0, param1 -> t0 */ { gen_op_mul_t0_t0_t0, gen_op_mul_t0_t0_t1, gen_op_mul_t0_t0_t2 }, +/* param0 -> t0, param1 -> t1 */ { gen_op_mul_t0_t1_t0, gen_op_mul_t0_t1_t1, gen_op_mul_t0_t1_t2 }, +/* param0 -> t0, param1 -> t2 */ { gen_op_mul_t0_t2_t0, gen_op_mul_t0_t2_t1, gen_op_mul_t0_t2_t2 } }, +/* param0 -> t1 */ { +/* param0 -> t1, param1 -> t0 */ { gen_op_mul_t1_t0_t0, gen_op_mul_t1_t0_t1, gen_op_mul_t1_t0_t2 }, +/* param0 -> t1, param1 -> t1 */ { gen_op_mul_t1_t1_t0, gen_op_mul_t1_t1_t1, gen_op_mul_t1_t1_t2 }, +/* param0 -> t1, param1 -> t2 */ { gen_op_mul_t1_t2_t0, gen_op_mul_t1_t2_t1, gen_op_mul_t1_t2_t2 } }, +/* param0 -> t2 */ { +/* param0 -> t2, param1 -> t0 */ { gen_op_mul_t2_t0_t0, gen_op_mul_t2_t0_t1, gen_op_mul_t2_t0_t2 }, +/* param0 -> t2, param1 -> t1 */ { gen_op_mul_t2_t1_t0, gen_op_mul_t2_t1_t1, gen_op_mul_t2_t1_t2 }, +/* param0 -> t2, param1 -> t2 */ { gen_op_mul_t2_t2_t0, gen_op_mul_t2_t2_t1, gen_op_mul_t2_t2_t2 } } }; + +void gen_l_mul(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) + return; + + if(!param[1] || !param[2]) { + clear_t[param_t[0]](opq, 1); + return; + } + + if(param_t[2] == T_NONE) + l_mul_imm_t_table[param_t[0]][param_t[1]](opq, 1, param[2]); + else + l_mul_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); +} + +static const generic_gen_op l_mulu_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { +/* param0 -> t0, param1 -> t0 */ { gen_op_mulu_t0_t0_t0, gen_op_mulu_t0_t0_t1, gen_op_mulu_t0_t0_t2 }, +/* param0 -> t0, param1 -> t1 */ { gen_op_mulu_t0_t1_t0, gen_op_mulu_t0_t1_t1, gen_op_mulu_t0_t1_t2 }, +/* param0 -> t0, param1 -> t2 */ { gen_op_mulu_t0_t2_t0, gen_op_mulu_t0_t2_t1, gen_op_mulu_t0_t2_t2 } }, +/* param0 -> t1 */ { +/* param0 -> t1, param1 -> t0 */ { gen_op_mulu_t1_t0_t0, gen_op_mulu_t1_t0_t1, gen_op_mulu_t1_t0_t2 }, +/* param0 -> t1, param1 -> t1 */ { gen_op_mulu_t1_t1_t0, gen_op_mulu_t1_t1_t1, gen_op_mulu_t1_t1_t2 }, +/* param0 -> t1, param1 -> t2 */ { gen_op_mulu_t1_t2_t0, gen_op_mulu_t1_t2_t1, gen_op_mulu_t1_t2_t2 } }, +/* param0 -> t2 */ { +/* param0 -> t2, param1 -> t0 */ { gen_op_mulu_t2_t0_t0, gen_op_mulu_t2_t0_t1, gen_op_mulu_t2_t0_t2 }, +/* param0 -> t2, param1 -> t1 */ { gen_op_mulu_t2_t1_t0, gen_op_mulu_t2_t1_t1, gen_op_mulu_t2_t1_t2 }, +/* param0 -> t2, param1 -> t2 */ { gen_op_mulu_t2_t2_t0, gen_op_mulu_t2_t2_t1, gen_op_mulu_t2_t2_t2 } } }; + +void gen_l_mulu(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) + return; + + if(!param[1] || !param[2]) { + clear_t[param_t[0]](opq, 1); + return; + } + + l_mulu_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); +} + +void gen_l_nop(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + /* Do parameter switch now */ + switch (param[0]) { + case NOP_NOP: + break; + case NOP_EXIT: + gen_op_nop_exit(opq, 1); + break; + case NOP_CNT_RESET: + /* FIXME: Since op_nop_reset calls handle_except, this instruction wont show + * up in the execution log, nor will the scheduler run */ + gen_op_nop_reset(opq, 1); + break; + case NOP_PRINTF: + gen_op_nop_printf(opq, 1); + break; + case NOP_REPORT: + gen_op_nop_report(opq, 1); + break; + default: + if((param[0] >= NOP_REPORT_FIRST) && (param[0] <= NOP_REPORT_LAST)) + gen_op_nop_report_imm(opq, 1, param[0] - NOP_REPORT_FIRST); + break; + } +} + +static const imm_gen_op l_or_imm_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_or_imm_t0_t0, gen_op_or_imm_t0_t1, gen_op_or_imm_t0_t2 }, +/* param0 -> t1 */ { gen_op_or_imm_t1_t0, gen_op_or_imm_t1_t1, gen_op_or_imm_t1_t2 }, +/* param0 -> t2 */ { gen_op_or_imm_t2_t0, gen_op_or_imm_t2_t1, gen_op_or_imm_t2_t2 } }; + +static const generic_gen_op l_or_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { +/* param0 -> t0, param1 -> t0 */ { NULL, gen_op_or_t0_t0_t1, gen_op_or_t0_t0_t2 }, +/* param0 -> t0, param1 -> t1 */ { gen_op_or_t0_t1_t0, gen_op_or_t0_t1_t1, gen_op_or_t0_t1_t2 }, +/* param0 -> t0, param1 -> t2 */ { gen_op_or_t0_t2_t0, gen_op_or_t0_t2_t1, gen_op_or_t0_t2_t2 } }, +/* param0 -> t1 */ { +/* param0 -> t1, param1 -> t0 */ { gen_op_or_t1_t0_t0, gen_op_or_t1_t0_t1, gen_op_or_t1_t0_t2 }, +/* param0 -> t1, param1 -> t1 */ { gen_op_or_t1_t1_t0, NULL, gen_op_or_t1_t1_t2 }, +/* param0 -> t1, param1 -> t2 */ { gen_op_or_t1_t2_t0, gen_op_or_t1_t2_t1, gen_op_or_t1_t2_t2 } }, +/* param0 -> t2 */ { +/* param0 -> t2, param1 -> t0 */ { gen_op_or_t2_t0_t0, gen_op_or_t2_t0_t1, gen_op_or_t2_t0_t2 }, +/* param0 -> t2, param1 -> t1 */ { gen_op_or_t2_t1_t0, gen_op_or_t2_t1_t1, gen_op_or_t2_t1_t2 }, +/* param0 -> t2, param1 -> t2 */ { gen_op_or_t2_t2_t0, gen_op_or_t2_t2_t1, NULL } } }; + +void gen_l_or(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) + return; + + if((param[0] == param[1] == param[2]) && (param_t[2] != T_NONE)) + return; + + if(!param[1] && !param[2]) { + clear_t[param_t[0]](opq, 1); + return; + } + + if(!param[2]) { + if((param_t[2] == T_NONE) && (param[0] == param[1])) + return; + move_t_t[param_t[0]][param_t[1]](opq, 1); + return; + } + + if(!param[1]) { + /* Check if we are moveing an immediate */ + if(param_t[2] == T_NONE) { + /* Yep, an immediate */ + mov_t_imm[param_t[0]](opq, 1, param[2]); + return; + } + /* Just another move */ + move_t_t[param_t[0]][param_t[2]](opq, 1); + return; + } + + if(param_t[2] == T_NONE) + l_or_imm_t_table[param_t[0]][param_t[1]](opq, 1, param[2]); + else + l_or_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); +} + +void gen_l_rfe(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(do_stats) + gen_op_analysis(opq, 1, 12, 0x24000000); + + gen_op_prep_rfe(opq, 1); + gen_op_do_sched(opq, 1); + gen_op_do_jump(opq, 1); +} + +/* FIXME: All store instructions should be optimised when the disposition = 0 */ + +static const imm_gen_op l_sb_clear_table[NUM_T_REGS] = + { gen_op_sb_clear_t0, gen_op_sb_clear_t1, gen_op_sb_clear_t2 }; + +static const imm_gen_op l_sb_imm_t_table[NUM_T_REGS] = + { gen_op_sb_imm_t0, gen_op_sb_imm_t1, gen_op_sb_imm_t2 }; + +static const imm_gen_op l_sb_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_sb_t0_t0, gen_op_sb_t0_t1, gen_op_sb_t0_t2 }, +/* param0 -> t1 */ { gen_op_sb_t1_t0, gen_op_sb_t1_t1, gen_op_sb_t1_t2 }, +/* param0 -> t2 */ { gen_op_sb_t2_t0, gen_op_sb_t2_t1, gen_op_sb_t2_t2 } }; + +void gen_l_sb(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[2]) { + if(!param[1]) { + gen_op_sb_clear_imm(opq, 1, param[0]); + return; + } + l_sb_clear_table[param_t[1]](opq, 1, param[0]); + return; + } + + if(!param[1]) { + /* Store the data to the immediate */ + l_sb_imm_t_table[param_t[2]](opq, 1, param[0]); + return; + } + + l_sb_t_table[param_t[1]][param_t[2]](opq, 1, param[0]); +} + +static const imm_gen_op l_sh_clear_table[NUM_T_REGS] = + { gen_op_sh_clear_t0, gen_op_sh_clear_t1, gen_op_sh_clear_t2 }; + +static const imm_gen_op l_sh_imm_t_table[NUM_T_REGS] = + { gen_op_sh_imm_t0, gen_op_sh_imm_t1, gen_op_sh_imm_t2 }; + +static const imm_gen_op l_sh_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_sh_t0_t0, gen_op_sh_t0_t1, gen_op_sh_t0_t2 }, +/* param0 -> t1 */ { gen_op_sh_t1_t0, gen_op_sh_t1_t1, gen_op_sh_t1_t2 }, +/* param0 -> t2 */ { gen_op_sh_t2_t0, gen_op_sh_t2_t1, gen_op_sh_t2_t2 } }; + +void gen_l_sh(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[2]) { + if(!param[1]) { + gen_op_sh_clear_imm(opq, 1, param[0]); + return; + } + l_sh_clear_table[param_t[1]](opq, 1, param[0]); + return; + } + + if(!param[1]) { + /* Store the data to the immediate */ + l_sh_imm_t_table[param_t[2]](opq, 1, param[0]); + return; + } + + l_sh_t_table[param_t[1]][param_t[2]](opq, 1, param[0]); +} + +static const imm_gen_op l_sw_clear_table[NUM_T_REGS] = + { gen_op_sw_clear_t0, gen_op_sw_clear_t1, gen_op_sw_clear_t2 }; + +static const imm_gen_op l_sw_imm_t_table[NUM_T_REGS] = + { gen_op_sw_imm_t0, gen_op_sw_imm_t1, gen_op_sw_imm_t2 }; + +static const imm_gen_op l_sw_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_sw_t0_t0, gen_op_sw_t0_t1, gen_op_sw_t0_t2 }, +/* param0 -> t1 */ { gen_op_sw_t1_t0, gen_op_sw_t1_t1, gen_op_sw_t1_t2 }, +/* param0 -> t2 */ { gen_op_sw_t2_t0, gen_op_sw_t2_t1, gen_op_sw_t2_t2 } }; + +void gen_l_sw(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[2]) { + if(!param[1]) { + gen_op_sw_clear_imm(opq, 1, param[0]); + return; + } + l_sw_clear_table[param_t[1]](opq, 1, param[0]); + return; + } + + if(!param[1]) { + /* Store the data to the immediate */ + l_sw_imm_t_table[param_t[2]](opq, 1, param[0]); + return; + } + + l_sw_t_table[param_t[1]][param_t[2]](opq, 1, param[0]); +} + +static const generic_gen_op l_sfeq_null_t_table[NUM_T_REGS] = + { gen_op_sfeq_null_t0, gen_op_sfeq_null_t1, gen_op_sfeq_null_t2 }; + +static const imm_gen_op l_sfeq_imm_t_table[NUM_T_REGS] = + { gen_op_sfeq_imm_t0, gen_op_sfeq_imm_t1, gen_op_sfeq_imm_t2 }; + +static const generic_gen_op l_sfeq_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_sfeq_t0_t0, gen_op_sfeq_t0_t1, gen_op_sfeq_t0_t2 }, +/* param0 -> t1 */ { gen_op_sfeq_t1_t0, gen_op_sfeq_t1_t1, gen_op_sfeq_t1_t2 }, +/* param0 -> t2 */ { gen_op_sfeq_t2_t0, gen_op_sfeq_t2_t1, gen_op_sfeq_t2_t2 } }; + +void gen_l_sfeq(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0] && !param[1]) { + gen_op_set_flag(opq, 1); + return; + } + + if(!param[0]) { + if(param_t[1] == T_NONE) { + if(!param[1]) + gen_op_set_flag(opq, 1); + else + gen_op_clear_flag(opq, 1); + } else + l_sfeq_null_t_table[param_t[1]](opq, 1); + return; + } + + if(!param[1]) { + l_sfeq_null_t_table[param_t[0]](opq, 1); + return; + } + + if(param_t[1] == T_NONE) + l_sfeq_imm_t_table[param_t[0]](opq, 1, param[1]); + else + l_sfeq_t_table[param_t[0]][param_t[1]](opq, 1); +} + +static const generic_gen_op l_sfges_null_t_table[NUM_T_REGS] = + { gen_op_sfges_null_t0, gen_op_sfges_null_t1, gen_op_sfges_null_t2 }; + +static const generic_gen_op l_sfles_null_t_table[NUM_T_REGS] = + { gen_op_sfles_null_t0, gen_op_sfles_null_t1, gen_op_sfles_null_t2 }; + +static const imm_gen_op l_sfges_imm_t_table[NUM_T_REGS] = + { gen_op_sfges_imm_t0, gen_op_sfges_imm_t1, gen_op_sfges_imm_t2 }; + +static const generic_gen_op l_sfges_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_sfges_t0_t0, gen_op_sfges_t0_t1, gen_op_sfges_t0_t2 }, +/* param0 -> t1 */ { gen_op_sfges_t1_t0, gen_op_sfges_t1_t1, gen_op_sfges_t1_t2 }, +/* param0 -> t2 */ { gen_op_sfges_t2_t0, gen_op_sfges_t2_t1, gen_op_sfges_t2_t2 } }; + +void gen_l_sfges(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0] && !param[1]) { + gen_op_set_flag(opq, 1); + return; + } + + if(!param[0]) { + /* sfles IS correct */ + if(param_t[1] == T_NONE) { + if(0 >= (orreg_t)param[1]) + gen_op_set_flag(opq, 1); + else + gen_op_clear_flag(opq, 1); + } else + l_sfles_null_t_table[param_t[1]](opq, 1); + return; + } + + if(!param[1]) { + l_sfges_null_t_table[param_t[0]](opq, 1); + return; + } + + if(param_t[1] == T_NONE) + l_sfges_imm_t_table[param_t[0]](opq, 1, param[1]); + else + l_sfges_t_table[param_t[0]][param_t[1]](opq, 1); +} + +static const generic_gen_op l_sfgeu_null_t_table[NUM_T_REGS] = + { gen_op_sfgeu_null_t0, gen_op_sfgeu_null_t1, gen_op_sfgeu_null_t2 }; + +static const generic_gen_op l_sfleu_null_t_table[NUM_T_REGS] = + { gen_op_sfleu_null_t0, gen_op_sfleu_null_t1, gen_op_sfleu_null_t2 }; + +static const imm_gen_op l_sfgeu_imm_t_table[NUM_T_REGS] = + { gen_op_sfgeu_imm_t0, gen_op_sfgeu_imm_t1, gen_op_sfgeu_imm_t2 }; + +static const generic_gen_op l_sfgeu_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_sfgeu_t0_t0, gen_op_sfgeu_t0_t1, gen_op_sfgeu_t0_t2 }, +/* param0 -> t1 */ { gen_op_sfgeu_t1_t0, gen_op_sfgeu_t1_t1, gen_op_sfgeu_t1_t2 }, +/* param0 -> t2 */ { gen_op_sfgeu_t2_t0, gen_op_sfgeu_t2_t1, gen_op_sfgeu_t2_t2 } }; + +void gen_l_sfgeu(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0] && !param[1]) { + gen_op_set_flag(opq, 1); + return; + } + + if(!param[0]) { + /* sfleu IS correct */ + if(param_t[1] == T_NONE) { + if(0 >= param[1]) + gen_op_set_flag(opq, 1); + else + gen_op_clear_flag(opq, 1); + } else + l_sfleu_null_t_table[param_t[1]](opq, 1); + return; + } + + if(!param[1]) { + l_sfgeu_null_t_table[param_t[0]](opq, 1); + return; + } + if(param_t[1] == T_NONE) + l_sfgeu_imm_t_table[param_t[0]](opq, 1, param[1]); + else + l_sfgeu_t_table[param_t[0]][param_t[1]](opq, 1); +} + +static const generic_gen_op l_sfgts_null_t_table[NUM_T_REGS] = + { gen_op_sfgts_null_t0, gen_op_sfgts_null_t1, gen_op_sfgts_null_t2 }; + +static const generic_gen_op l_sflts_null_t_table[NUM_T_REGS] = + { gen_op_sflts_null_t0, gen_op_sflts_null_t1, gen_op_sflts_null_t2 }; + +static const imm_gen_op l_sfgts_imm_t_table[NUM_T_REGS] = + { gen_op_sfgts_imm_t0, gen_op_sfgts_imm_t1, gen_op_sfgts_imm_t2 }; + +static const generic_gen_op l_sfgts_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_sfgts_t0_t0, gen_op_sfgts_t0_t1, gen_op_sfgts_t0_t2 }, +/* param0 -> t1 */ { gen_op_sfgts_t1_t0, gen_op_sfgts_t1_t1, gen_op_sfgts_t1_t2 }, +/* param0 -> t2 */ { gen_op_sfgts_t2_t0, gen_op_sfgts_t2_t1, gen_op_sfgts_t2_t2 } }; + +void gen_l_sfgts(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0] && !param[1]) { + gen_op_clear_flag(opq, 1); + return; + } + + if(!param[0]) { + /* sflts IS correct */ + if(param_t[1] == T_NONE) { + if(0 > (orreg_t)param[1]) + gen_op_set_flag(opq, 1); + else + gen_op_clear_flag(opq, 1); + } else + l_sflts_null_t_table[param_t[1]](opq, 1); + return; + } + + if(!param[1]) { + l_sfgts_null_t_table[param_t[0]](opq, 1); + return; + } + + if(param_t[1] == T_NONE) + l_sfgts_imm_t_table[param_t[0]](opq, 1, param[1]); + else + l_sfgts_t_table[param_t[0]][param_t[1]](opq, 1); +} + +static const generic_gen_op l_sfgtu_null_t_table[NUM_T_REGS] = + { gen_op_sfgtu_null_t0, gen_op_sfgtu_null_t1, gen_op_sfgtu_null_t2 }; + +static const generic_gen_op l_sfltu_null_t_table[NUM_T_REGS] = + { gen_op_sfltu_null_t0, gen_op_sfltu_null_t1, gen_op_sfltu_null_t2 }; + +static const imm_gen_op l_sfgtu_imm_t_table[NUM_T_REGS] = + { gen_op_sfgtu_imm_t0, gen_op_sfgtu_imm_t1, gen_op_sfgtu_imm_t2 }; + +static const generic_gen_op l_sfgtu_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_sfgtu_t0_t0, gen_op_sfgtu_t0_t1, gen_op_sfgtu_t0_t2 }, +/* param0 -> t1 */ { gen_op_sfgtu_t1_t0, gen_op_sfgtu_t1_t1, gen_op_sfgtu_t1_t2 }, +/* param0 -> t2 */ { gen_op_sfgtu_t2_t0, gen_op_sfgtu_t2_t1, gen_op_sfgtu_t2_t2 } }; + +void gen_l_sfgtu(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0] && !param[1]) { + gen_op_clear_flag(opq, 1); + return; + } + + if(!param[0]) { + /* sfltu IS correct */ + if(param_t[1] == T_NONE) { + if(0 > param[1]) + gen_op_set_flag(opq, 1); + else + gen_op_clear_flag(opq, 1); + } else + l_sfltu_null_t_table[param_t[1]](opq, 1); + return; + } + + if(!param[1]) { + l_sfgtu_null_t_table[param_t[0]](opq, 1); + return; + } + + if(param_t[1] == T_NONE) + l_sfgtu_imm_t_table[param_t[0]](opq, 1, param[1]); + else + l_sfgtu_t_table[param_t[0]][param_t[1]](opq, 1); +} + +static const imm_gen_op l_sfles_imm_t_table[NUM_T_REGS] = + { gen_op_sfles_imm_t0, gen_op_sfles_imm_t1, gen_op_sfles_imm_t2 }; + +static const generic_gen_op l_sfles_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_sfles_t0_t0, gen_op_sfles_t0_t1, gen_op_sfles_t0_t2 }, +/* param0 -> t1 */ { gen_op_sfles_t1_t0, gen_op_sfles_t1_t1, gen_op_sfles_t1_t2 }, +/* param0 -> t2 */ { gen_op_sfles_t2_t0, gen_op_sfles_t2_t1, gen_op_sfles_t2_t2 } }; + +void gen_l_sfles(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0] && !param[1]) { + gen_op_set_flag(opq, 1); + return; + } + + if(!param[0]) { + /* sfges IS correct */ + if(param_t[1] == T_NONE) { + if(0 <= (orreg_t)param[1]) + gen_op_set_flag(opq, 1); + else + gen_op_clear_flag(opq, 1); + } else + l_sfges_null_t_table[param_t[1]](opq, 1); + return; + } + + if(!param[1]) { + l_sfles_null_t_table[param_t[0]](opq, 1); + return; + } + + if(param_t[1] == T_NONE) + l_sfles_imm_t_table[param_t[0]](opq, 1, param[1]); + else + l_sfles_t_table[param_t[0]][param_t[1]](opq, 1); +} + +static const imm_gen_op l_sfleu_imm_t_table[NUM_T_REGS] = + { gen_op_sfleu_imm_t0, gen_op_sfleu_imm_t1, gen_op_sfleu_imm_t2 }; + +static const generic_gen_op l_sfleu_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_sfleu_t0_t0, gen_op_sfleu_t0_t1, gen_op_sfleu_t0_t2 }, +/* param0 -> t1 */ { gen_op_sfleu_t1_t0, gen_op_sfleu_t1_t1, gen_op_sfleu_t1_t2 }, +/* param0 -> t2 */ { gen_op_sfleu_t2_t0, gen_op_sfleu_t2_t1, gen_op_sfleu_t2_t2 } }; + +void gen_l_sfleu(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0] && !param[1]) { + gen_op_set_flag(opq, 1); + return; + } + + if(!param[0]) { + /* sfleu IS correct */ + if(param_t[1] == T_NONE) { + if(0 <= param[1]) + gen_op_set_flag(opq, 1); + else + gen_op_clear_flag(opq, 1); + } else + l_sfgeu_null_t_table[param_t[1]](opq, 1); + return; + } + + if(!param[1]) { + l_sfleu_null_t_table[param_t[0]](opq, 1); + return; + } + + if(param_t[1] == T_NONE) + l_sfleu_imm_t_table[param_t[0]](opq, 1, param[1]); + else + l_sfleu_t_table[param_t[0]][param_t[1]](opq, 1); +} + +static const imm_gen_op l_sflts_imm_t_table[NUM_T_REGS] = + { gen_op_sflts_imm_t0, gen_op_sflts_imm_t1, gen_op_sflts_imm_t2 }; + +static const generic_gen_op l_sflts_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_sflts_t0_t0, gen_op_sflts_t0_t1, gen_op_sflts_t0_t2 }, +/* param0 -> t1 */ { gen_op_sflts_t1_t0, gen_op_sflts_t1_t1, gen_op_sflts_t1_t2 }, +/* param0 -> t2 */ { gen_op_sflts_t2_t0, gen_op_sflts_t2_t1, gen_op_sflts_t2_t2 } }; + +void gen_l_sflts(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0] && !param[1]) { + gen_op_clear_flag(opq, 1); + return; + } + + if(!param[0]) { + /* sfgts IS correct */ + if(param_t[1] == T_NONE) { + if(0 < (orreg_t)param[1]) + gen_op_set_flag(opq, 1); + else + gen_op_clear_flag(opq, 1); + } else + l_sfgts_null_t_table[param_t[1]](opq, 1); + return; + } + + if(!param[1]) { + l_sflts_null_t_table[param_t[0]](opq, 1); + return; + } + + if(param_t[1] == T_NONE) + l_sflts_imm_t_table[param_t[0]](opq, 1, param[1]); + else + l_sflts_t_table[param_t[0]][param_t[1]](opq, 1); +} + +static const imm_gen_op l_sfltu_imm_t_table[NUM_T_REGS] = + { gen_op_sfltu_imm_t0, gen_op_sfltu_imm_t1, gen_op_sfltu_imm_t2 }; + +static const generic_gen_op l_sfltu_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_sfltu_t0_t0, gen_op_sfltu_t0_t1, gen_op_sfltu_t0_t2 }, +/* param0 -> t1 */ { gen_op_sfltu_t1_t0, gen_op_sfltu_t1_t1, gen_op_sfltu_t1_t2 }, +/* param0 -> t2 */ { gen_op_sfltu_t2_t0, gen_op_sfltu_t2_t1, gen_op_sfltu_t2_t2 } }; + +void gen_l_sfltu(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0] && !param[1]) { + gen_op_clear_flag(opq, 1); + return; + } + + if(!param[0]) { + /* sfgtu IS correct */ + if(param_t[1] == T_NONE) { + if(0 < param[1]) + gen_op_set_flag(opq, 1); + else + gen_op_clear_flag(opq, 1); + } else + l_sfgtu_null_t_table[param_t[1]](opq, 1); + return; + } + + if(!param[1]) { + l_sfltu_null_t_table[param_t[0]](opq, 1); + return; + } + + if(param_t[1] == T_NONE) + l_sfltu_imm_t_table[param_t[0]](opq, 1, param[1]); + else + l_sfltu_t_table[param_t[0]][param_t[1]](opq, 1); +} + +static const generic_gen_op l_sfne_null_t_table[NUM_T_REGS] = + { gen_op_sfne_null_t0, gen_op_sfne_null_t1, gen_op_sfne_null_t2 }; + +static const imm_gen_op l_sfne_imm_t_table[NUM_T_REGS] = + { gen_op_sfne_imm_t0, gen_op_sfne_imm_t1, gen_op_sfne_imm_t2 }; + +static const generic_gen_op l_sfne_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_sfne_t0_t0, gen_op_sfne_t0_t1, gen_op_sfne_t0_t2 }, +/* param0 -> t1 */ { gen_op_sfne_t1_t0, gen_op_sfne_t1_t1, gen_op_sfne_t1_t2 }, +/* param0 -> t2 */ { gen_op_sfne_t2_t0, gen_op_sfne_t2_t1, gen_op_sfne_t2_t2 } }; + +void gen_l_sfne(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0] && !param[1]) { + gen_op_set_flag(opq, 1); + return; + } + + if(!param[0]) { + if(param_t[1] == T_NONE) + if(param[1]) + gen_op_set_flag(opq, 1); + else + gen_op_clear_flag(opq, 1); + else + l_sfne_null_t_table[param_t[1]](opq, 1); + return; + } + + if(!param[1]) { + l_sfne_null_t_table[param_t[0]](opq, 1); + return; + } + + if(param_t[1] == T_NONE) + l_sfne_imm_t_table[param_t[0]](opq, 1, param[1]); + else + l_sfne_t_table[param_t[0]][param_t[1]](opq, 1); +} + +static const imm_gen_op l_sll_imm_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_sll_imm_t0_t0, gen_op_sll_imm_t0_t1, gen_op_sll_imm_t0_t2 }, +/* param0 -> t1 */ { gen_op_sll_imm_t1_t0, gen_op_sll_imm_t1_t1, gen_op_sll_imm_t1_t2 }, +/* param0 -> t2 */ { gen_op_sll_imm_t2_t0, gen_op_sll_imm_t2_t1, gen_op_sll_imm_t2_t2 } }; + +static const generic_gen_op l_sll_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { +/* param0 -> t0, param1 -> t0 */ { gen_op_sll_t0_t0_t0, gen_op_sll_t0_t0_t1, gen_op_sll_t0_t0_t2 }, +/* param0 -> t0, param1 -> t1 */ { gen_op_sll_t0_t1_t0, gen_op_sll_t0_t1_t1, gen_op_sll_t0_t1_t2 }, +/* param0 -> t0, param1 -> t2 */ { gen_op_sll_t0_t2_t0, gen_op_sll_t0_t2_t1, gen_op_sll_t0_t2_t2 } }, +/* param0 -> t1 */ { +/* param0 -> t1, param1 -> t0 */ { gen_op_sll_t1_t0_t0, gen_op_sll_t1_t0_t1, gen_op_sll_t1_t0_t2 }, +/* param0 -> t1, param1 -> t1 */ { gen_op_sll_t1_t1_t0, gen_op_sll_t1_t1_t1, gen_op_sll_t1_t1_t2 }, +/* param0 -> t1, param1 -> t2 */ { gen_op_sll_t1_t2_t0, gen_op_sll_t1_t2_t1, gen_op_sll_t1_t2_t2 } }, +/* param0 -> t2 */ { +/* param0 -> t2, param1 -> t0 */ { gen_op_sll_t2_t0_t0, gen_op_sll_t2_t0_t1, gen_op_sll_t2_t0_t2 }, +/* param0 -> t2, param1 -> t1 */ { gen_op_sll_t2_t1_t0, gen_op_sll_t2_t1_t1, gen_op_sll_t2_t1_t2 }, +/* param0 -> t2, param1 -> t2 */ { gen_op_sll_t2_t2_t0, gen_op_sll_t2_t2_t1, gen_op_sll_t2_t2_t2 } } }; + +void gen_l_sll(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) + return; + + if(!param[1]) { + clear_t[param_t[0]](opq, 1); + return; + } + + if(!param[2]) { + move_t_t[param_t[0]][param_t[1]](opq, 1); + return; + } + + if(param_t[2] == T_NONE) + l_sll_imm_t_table[param_t[0]][param_t[1]](opq, 1, param[2]); + else + l_sll_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); +} + +static const imm_gen_op l_sra_imm_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_sra_imm_t0_t0, gen_op_sra_imm_t0_t1, gen_op_sra_imm_t0_t2 }, +/* param0 -> t1 */ { gen_op_sra_imm_t1_t0, gen_op_sra_imm_t1_t1, gen_op_sra_imm_t1_t2 }, +/* param0 -> t2 */ { gen_op_sra_imm_t2_t0, gen_op_sra_imm_t2_t1, gen_op_sra_imm_t2_t2 } }; + +static const generic_gen_op l_sra_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { +/* param0 -> t0, param1 -> t0 */ { gen_op_sra_t0_t0_t0, gen_op_sra_t0_t0_t1, gen_op_sra_t0_t0_t2 }, +/* param0 -> t0, param1 -> t1 */ { gen_op_sra_t0_t1_t0, gen_op_sra_t0_t1_t1, gen_op_sra_t0_t1_t2 }, +/* param0 -> t0, param1 -> t2 */ { gen_op_sra_t0_t2_t0, gen_op_sra_t0_t2_t1, gen_op_sra_t0_t2_t2 } }, +/* param0 -> t1 */ { +/* param0 -> t1, param1 -> t0 */ { gen_op_sra_t1_t0_t0, gen_op_sra_t1_t0_t1, gen_op_sra_t1_t0_t2 }, +/* param0 -> t1, param1 -> t1 */ { gen_op_sra_t1_t1_t0, gen_op_sra_t1_t1_t1, gen_op_sra_t1_t1_t2 }, +/* param0 -> t1, param1 -> t2 */ { gen_op_sra_t1_t2_t0, gen_op_sra_t1_t2_t1, gen_op_sra_t1_t2_t2 } }, +/* param0 -> t2 */ { +/* param0 -> t2, param1 -> t0 */ { gen_op_sra_t2_t0_t0, gen_op_sra_t2_t0_t1, gen_op_sra_t2_t0_t2 }, +/* param0 -> t2, param1 -> t1 */ { gen_op_sra_t2_t1_t0, gen_op_sra_t2_t1_t1, gen_op_sra_t2_t1_t2 }, +/* param0 -> t2, param1 -> t2 */ { gen_op_sra_t2_t2_t0, gen_op_sra_t2_t2_t1, gen_op_sra_t2_t2_t2 } } }; + +void gen_l_sra(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) + return; + + if(!param[1]) { + clear_t[param_t[0]](opq, 1); + return; + } + + if(!param[2]) { + move_t_t[param_t[0]][param_t[1]](opq, 1); + return; + } + + if(param_t[2] == T_NONE) + l_sra_imm_t_table[param_t[0]][param_t[1]](opq, 1, param[2]); + else + l_sra_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); +} + +static const imm_gen_op l_srl_imm_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_srl_imm_t0_t0, gen_op_srl_imm_t0_t1, gen_op_srl_imm_t0_t2 }, +/* param0 -> t1 */ { gen_op_srl_imm_t1_t0, gen_op_srl_imm_t1_t1, gen_op_srl_imm_t1_t2 }, +/* param0 -> t2 */ { gen_op_srl_imm_t2_t0, gen_op_srl_imm_t2_t1, gen_op_srl_imm_t2_t2 } }; + +static const generic_gen_op l_srl_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { +/* param0 -> t0, param1 -> t0 */ { gen_op_srl_t0_t0_t0, gen_op_srl_t0_t0_t1, gen_op_srl_t0_t0_t2 }, +/* param0 -> t0, param1 -> t1 */ { gen_op_srl_t0_t1_t0, gen_op_srl_t0_t1_t1, gen_op_srl_t0_t1_t2 }, +/* param0 -> t0, param1 -> t2 */ { gen_op_srl_t0_t2_t0, gen_op_srl_t0_t2_t1, gen_op_srl_t0_t2_t2 } }, +/* param0 -> t1 */ { +/* param0 -> t1, param1 -> t0 */ { gen_op_srl_t1_t0_t0, gen_op_srl_t1_t0_t1, gen_op_srl_t1_t0_t2 }, +/* param0 -> t1, param1 -> t1 */ { gen_op_srl_t1_t1_t0, gen_op_srl_t1_t1_t1, gen_op_srl_t1_t1_t2 }, +/* param0 -> t1, param1 -> t2 */ { gen_op_srl_t1_t2_t0, gen_op_srl_t1_t2_t1, gen_op_srl_t1_t2_t2 } }, +/* param0 -> t2 */ { +/* param0 -> t2, param1 -> t0 */ { gen_op_srl_t2_t0_t0, gen_op_srl_t2_t0_t1, gen_op_srl_t2_t0_t2 }, +/* param0 -> t2, param1 -> t1 */ { gen_op_srl_t2_t1_t0, gen_op_srl_t2_t1_t1, gen_op_srl_t2_t1_t2 }, +/* param0 -> t2, param1 -> t2 */ { gen_op_srl_t2_t2_t0, gen_op_srl_t2_t2_t1, gen_op_srl_t2_t2_t2 } } }; + +void gen_l_srl(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) + return; + + if(!param[1]) { + clear_t[param_t[0]](opq, 1); + return; + } + + if(!param[2]) { + move_t_t[param_t[0]][param_t[1]](opq, 1); + return; + } + + if(param_t[2] == T_NONE) + l_srl_imm_t_table[param_t[0]][param_t[1]](opq, 1, param[2]); + else + l_srl_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); +} + +static const generic_gen_op l_neg_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_neg_t0_t0, gen_op_neg_t0_t1, gen_op_neg_t0_t2 }, +/* param0 -> t1 */ { gen_op_neg_t1_t0, gen_op_neg_t1_t1, gen_op_neg_t1_t2 }, +/* param0 -> t2 */ { gen_op_neg_t2_t0, gen_op_neg_t2_t1, gen_op_neg_t2_t2 } }; + +static const generic_gen_op l_sub_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { +/* param0 -> t0, param1 -> t0 */ { gen_op_sub_t0_t0_t0, gen_op_sub_t0_t0_t1, gen_op_sub_t0_t0_t2 }, +/* param0 -> t0, param1 -> t1 */ { gen_op_sub_t0_t1_t0, gen_op_sub_t0_t1_t1, gen_op_sub_t0_t1_t2 }, +/* param0 -> t0, param1 -> t2 */ { gen_op_sub_t0_t2_t0, gen_op_sub_t0_t2_t1, gen_op_sub_t0_t2_t2 } }, +/* param0 -> t1 */ { +/* param0 -> t1, param1 -> t0 */ { gen_op_sub_t1_t0_t0, gen_op_sub_t1_t0_t1, gen_op_sub_t1_t0_t2 }, +/* param0 -> t1, param1 -> t1 */ { gen_op_sub_t1_t1_t0, gen_op_sub_t1_t1_t1, gen_op_sub_t1_t1_t2 }, +/* param0 -> t1, param1 -> t2 */ { gen_op_sub_t1_t2_t0, gen_op_sub_t1_t2_t1, gen_op_sub_t1_t2_t2 } }, +/* param0 -> t2 */ { +/* param0 -> t2, param1 -> t0 */ { gen_op_sub_t2_t0_t0, gen_op_sub_t2_t0_t1, gen_op_sub_t2_t0_t2 }, +/* param0 -> t2, param1 -> t1 */ { gen_op_sub_t2_t1_t0, gen_op_sub_t2_t1_t1, gen_op_sub_t2_t1_t2 }, +/* param0 -> t2, param1 -> t2 */ { gen_op_sub_t2_t2_t0, gen_op_sub_t2_t2_t1, gen_op_sub_t2_t2_t2 } } }; + +void gen_l_sub(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) + return; + + if((param_t[2] != T_NONE) && (param[1] == param[2])) { + clear_t[param_t[0]](opq, 1); + return; + } + + if(!param[1] && !param[2]) { + clear_t[param_t[0]](opq, 1); + return; + } + + if(!param[1]) { + if(param_t[2] == T_NONE) + mov_t_imm[param_t[0]](opq, 1, -param[2]); + else + l_neg_t_table[param_t[0]][param_t[2]](opq, 1); + return; + } + + if(!param[2]) { + move_t_t[param_t[0]][param_t[1]](opq, 1); + return; + } + + l_sub_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); +} + +/* FIXME: This will not work if the l.sys is in a delay slot */ +void gen_l_sys(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(do_stats) + gen_op_analysis(opq, 1, 7, 0x20000000 | param[0]); + + if(!delay_slot) + gen_op_prep_sys(opq, 1); + else + gen_op_prep_sys_delay(opq, 1); + + gen_op_do_sched(opq, 1); + gen_op_do_jump(opq, 1); +} + +/* FIXME: This will not work if the l.trap is in a delay slot */ +void gen_l_trap(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(do_stats) + gen_op_analysis(opq, 1, 8, 0x22000000); + + if(!delay_slot) + gen_op_prep_trap(opq, 1); + else + gen_op_prep_trap_delay(opq, 1); +} + +static const imm_gen_op l_xor_imm_t_table[NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { gen_op_xor_imm_t0_t0, gen_op_xor_imm_t0_t1, gen_op_xor_imm_t0_t2 }, +/* param0 -> t1 */ { gen_op_xor_imm_t1_t0, gen_op_xor_imm_t1_t1, gen_op_xor_imm_t1_t2 }, +/* param0 -> t2 */ { gen_op_xor_imm_t2_t0, gen_op_xor_imm_t2_t1, gen_op_xor_imm_t2_t2 } }; + +static const generic_gen_op l_xor_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { +/* param0 -> t0 */ { +/* param0 -> t0, param1 -> t0 */ { gen_op_xor_t0_t0_t0, gen_op_xor_t0_t0_t1, gen_op_xor_t0_t0_t2 }, +/* param0 -> t0, param1 -> t1 */ { gen_op_xor_t0_t1_t0, gen_op_xor_t0_t1_t1, gen_op_xor_t0_t1_t2 }, +/* param0 -> t0, param1 -> t2 */ { gen_op_xor_t0_t2_t0, gen_op_xor_t0_t2_t1, gen_op_xor_t0_t2_t2 } }, +/* param0 -> t1 */ { +/* param0 -> t1, param1 -> t0 */ { gen_op_xor_t1_t0_t0, gen_op_xor_t1_t0_t1, gen_op_xor_t1_t0_t2 }, +/* param0 -> t1, param1 -> t1 */ { gen_op_xor_t1_t1_t0, gen_op_xor_t1_t1_t1, gen_op_xor_t1_t1_t2 }, +/* param0 -> t1, param1 -> t2 */ { gen_op_xor_t1_t2_t0, gen_op_xor_t1_t2_t1, gen_op_xor_t1_t2_t2 } }, +/* param0 -> t2 */ { +/* param0 -> t2, param1 -> t0 */ { gen_op_xor_t2_t0_t0, gen_op_xor_t2_t0_t1, gen_op_xor_t2_t0_t2 }, +/* param0 -> t2, param1 -> t1 */ { gen_op_xor_t2_t1_t0, gen_op_xor_t2_t1_t1, gen_op_xor_t2_t1_t2 }, +/* param0 -> t2, param1 -> t2 */ { gen_op_xor_t2_t2_t0, gen_op_xor_t2_t2_t1, gen_op_xor_t2_t2_t2 } } }; + +void gen_l_xor(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!param[0]) + return; + + if((param_t[2] != T_NONE) && (param[1] == param[2])) { + clear_t[param_t[0]](opq, 1); + return; + } + + if(!param[2]) { + if((param_t[2] == T_NONE) && (param[0] == param[1])) + return; + move_t_t[param_t[0]][param_t[1]](opq, 1); + return; + } + + if(!param[1]) { + if(param_t[2] == T_NONE) { + mov_t_imm[param_t[0]](opq, 1, param[2]); + return; + } + move_t_t[param_t[0]][param_t[2]](opq, 1); + return; + } + + if(param_t[2] == T_NONE) + l_xor_imm_t_table[param_t[0]][param_t[1]](opq, 1, param[2]); + else + l_xor_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); +} + +void gen_l_invalid(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + if(!delay_slot) + gen_op_illegal(opq, 1); + else + gen_op_illegal_delay(opq, 1); +} + +/*----------------------------------[ Floating point instructions (stubs) ]---*/ +void gen_lf_add_s(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + gen_l_invalid(opq, param_t, param, delay_slot); +} + +void gen_lf_div_s(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + gen_l_invalid(opq, param_t, param, delay_slot); +} + +void gen_lf_ftoi_s(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + gen_l_invalid(opq, param_t, param, delay_slot); +} + +void gen_lf_itof_s(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + gen_l_invalid(opq, param_t, param, delay_slot); +} + +void gen_lf_madd_s(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + gen_l_invalid(opq, param_t, param, delay_slot); +} + +void gen_lf_mul_s(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + gen_l_invalid(opq, param_t, param, delay_slot); +} + +void gen_lf_rem_s(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + gen_l_invalid(opq, param_t, param, delay_slot); +} + +void gen_lf_sfeq_s(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + gen_l_invalid(opq, param_t, param, delay_slot); +} + +void gen_lf_sfge_s(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + gen_l_invalid(opq, param_t, param, delay_slot); +} + +void gen_lf_sfgt_s(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + gen_l_invalid(opq, param_t, param, delay_slot); +} + +void gen_lf_sfle_s(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + gen_l_invalid(opq, param_t, param, delay_slot); +} + +void gen_lf_sflt_s(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + gen_l_invalid(opq, param_t, param, delay_slot); +} + +void gen_lf_sfne_s(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + gen_l_invalid(opq, param_t, param, delay_slot); +} + +void gen_lf_sub_s(struct op_queue *opq, int param_t[3], orreg_t param[3], + int delay_slot) +{ + gen_l_invalid(opq, param_t, param, delay_slot); +} + Index: dyn32_defs.h =================================================================== --- dyn32_defs.h (nonexistent) +++ dyn32_defs.h (revision 1765) @@ -0,0 +1,116 @@ +/* dyn32_defs.h -- Definitions for the dynamic execution model + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +struct op_queue { + unsigned int num_ops; + unsigned int ops_len; + unsigned int *ops; + unsigned int num_ops_param; + unsigned int ops_param_len; + unsigned int *ops_param; + unsigned int jump_local; /* Parameter index that holds the location of the jump */ + oraddr_t jump_local_loc; /* Location to jump to (relative to start of page */ + unsigned int not_jump_loc; /* Location to jump if not jumping (l.bf/l.bnf) */ + int xref; /* Is this location cross referenced? */ + oraddr_t insn_addr; /* Physical address of the instruction */ + unsigned int reg_t[3]; /* Which registers are in the temporaries (before the instruction)? */ + unsigned int reg_t_d[3]; /* Which registers are in the temporaries (after the instruction? */ + struct op_queue *prev; + struct op_queue *next; +}; + +void gen_l_add PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_addc PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_and PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_bf PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_bnf PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_cmov PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_cust1 PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_cust2 PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_cust3 PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_cust4 PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_div PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_divu PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_extbs PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_extbz PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_exths PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_exthz PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_extws PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_extwz PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_ff1 PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_j PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_jal PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_jr PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_jalr PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_lbs PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_lbz PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_lhs PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_lhz PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_lws PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_lwz PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_mac PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_macrc PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_mfspr PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_movhi PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_msb PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_mtspr PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_mul PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_mulu PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_nop PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_or PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_rfe PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_sb PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_sh PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_sw PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_sfeq PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_sfges PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_sfgeu PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_sfgts PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_sfgtu PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_sfles PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_sfleu PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_sflts PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_sfltu PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_sfne PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_sll PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_sra PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_srl PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_sub PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_sys PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_trap PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_xor PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_l_invalid PARAMS((struct op_queue *, int *, orreg_t *, int)); + +void gen_lf_add_s PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_lf_div_s PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_lf_ftoi_s PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_lf_itof_s PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_lf_madd_s PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_lf_mul_s PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_lf_rem_s PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_lf_sfeq_s PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_lf_sfge_s PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_lf_sfgt_s PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_lf_sfle_s PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_lf_sflt_s PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_lf_sfne_s PARAMS((struct op_queue *, int *, orreg_t *, int)); +void gen_lf_sub_s PARAMS((struct op_queue *, int *, orreg_t *, int)); +void l_none(struct op_queue *opq, int *param_t, orreg_t *param, int delay_slot); + Index: op.c =================================================================== --- op.c (nonexistent) +++ op.c (revision 1765) @@ -0,0 +1,1342 @@ +/* op.c -- Micro operations for the recompiler + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include +#include +#include + +#include "config.h" + +#ifdef HAVE_INTTYPES_H +#include +#endif + +#include "port.h" +#include "arch.h" +#include "spr_defs.h" +#include "opcode/or32.h" +#include "sim-config.h" +#include "except.h" +#include "abstract.h" +#include "execute.h" +#include "sprs.h" +#include "sched.h" + +#include "op_support.h" + +#include "i386_regs.h" + +#include "dyn_rec.h" + +/* This must be here since the function in op_i386.h use this variable */ +register struct cpu_state *env asm(CPU_STATE_REG); + +#include "op_i386.h" + +/* + * WARNING: Before going of and wildly editing everything in this file remember + * the following about its contents: + * 1) The `functions' don't EVER return. In otherwords haveing return state- + * ments _anywere_ in this file is likely not to work. This is because + * dyngen just strips away the ret from the end of the function and just uses + * the function `body'. If a ret statement is executed _anyware_ inside the + * dynamicly generated code, then it is undefined were we shall jump to. + * 2) Because of 1), try not to have overly complicated functions. In too + * complicated functions, gcc may decide to generate premature `exits'. This + * is what passing the -fno-reorder-blocks command line switch to gcc helps + * with. This is ofcourse not desired and is rather flaky as we don't (and + * can't) control the kind of code that gcc generates: It may work for one + * and break for another. The less branches there are the less likely it is + * that a premature return shall occur. + * 3) If gcc decides that it is going to be a basterd then it will optimise a + * very simple condition (if/switch) with a premature exit. But gcc can't + * fuck ME over! Just stick a FORCE_RET; at the END of the offending + * function. + * 4) All operations must start with `op_'. dyngen ignores all other functions. + * 5) Local variables are depriciated: They hinder performance. + * 6) Function calls are expensive as the stack has to be shifted (twice). + */ + +/*#define __or_dynop __attribute__((noreturn))*/ +#define __or_dynop + +/* Temporaries to hold the (simulated) registers in */ +register uint32_t t0 asm(T0_REG); +register uint32_t t1 asm(T1_REG); +register uint32_t t2 asm(T2_REG); + +#define OP_PARAM1 ((uorreg_t)(&__op_param1)) +#define OP_PARAM2 ((uorreg_t)(&__op_param2)) +#define OP_PARAM3 ((uorreg_t)(&__op_param3)) + +extern uorreg_t __op_param1; +extern uorreg_t __op_param2; +extern uorreg_t __op_param3; + +#define xglue(x, y) x ## y +#define glue(x, y) xglue(x, y) + +/* Helper function. Whenever we escape the recompiled code and there is a + * potential that an exception may happen this function must be called */ +static inline void save_t_temporary(void) +{ + env->t0 = t0; + env->t1 = t1; + env->t2 = t2; +} + +/* Wrapper around do_scheduler. This is needed because op_do_sched must be as + * small as possible. */ +void do_sched_wrap(void) +{ + save_t_temporary(); + upd_sim_cycles(); + do_scheduler(); +} + +/* do_scheduler wrapper for instructions that are in the delay slot */ +void do_sched_wrap_delay(void) +{ + save_t_temporary(); + upd_sim_cycles(); + env->ts_current = 1; + /* The PC gets set to the location of the jump, but do_sched increments that + * so pull it back here to point to the right location again. This could be + * done in op_add_pc/op_set_pc_pc_delay but that would enlarge the recompiled + * code. */ + //env->pc -= 4; + do_scheduler(); + env->ts_current = 0; +} + +void enter_dyn_code(oraddr_t addr, struct dyn_page *dp) +{ + uint16_t reg; + + addr &= config.immu.pagesize - 1; + addr >>= 2; + + reg = dp->ts_bound[addr]; + + if(reg & 0x1f) + t0 = cpu_state.reg[reg & 0x1f]; + + if((reg >> 5) & 0x1f) + t1 = cpu_state.reg[(reg >> 5) & 0x1f]; + + if((reg >> 10) & 0x1f) + t2 = cpu_state.reg[(reg >> 10) & 0x1f]; + + or_longjmp(dp->locs[addr]); +} + +__or_dynop void op_t0_imm(void) +{ + t0 = OP_PARAM1; +} + +__or_dynop void op_t1_imm(void) +{ + t1 = OP_PARAM1; +} + +__or_dynop void op_t2_imm(void) +{ + t2 = OP_PARAM1; +} + +__or_dynop void op_clear_t0(void) +{ + t0 = 0; +} + +__or_dynop void op_clear_t1(void) +{ + t1 = 0; +} + +__or_dynop void op_clear_t2(void) +{ + t2 = 0; +} + +__or_dynop void op_move_t0_t1(void) +{ + t0 = t1; +} + +__or_dynop void op_move_t0_t2(void) +{ + t0 = t2; +} + +__or_dynop void op_move_t1_t0(void) +{ + t1 = t0; +} + +__or_dynop void op_move_t1_t2(void) +{ + t1 = t2; +} + +__or_dynop void op_move_t2_t0(void) +{ + t2 = t0; +} + +__or_dynop void op_move_t2_t1(void) +{ + t2 = t1; +} + +__or_dynop void op_set_pc_pc_delay(void) +{ + env->sprs[SPR_PPC] = get_pc(); + /* pc_delay is pulled back 4 since imediatly after this is run, the scheduler + * runs which also increments it by 4 */ + set_pc(env->pc_delay - 4); +} + +__or_dynop void op_set_pc_delay_imm(void) +{ + env->pc_delay = get_pc() + (orreg_t)OP_PARAM1; + env->delay_insn = 1; +} + +__or_dynop void op_set_pc_delay_pc(void) +{ + env->pc_delay = get_pc(); + env->delay_insn = 1; +} + +__or_dynop void op_clear_pc_delay(void) +{ + env->pc_delay = 0; + env->delay_insn = 1; +} + +__or_dynop void op_do_jump(void) +{ + do_jump(get_pc()); +} + +__or_dynop void op_do_jump_delay(void) +{ + do_jump(env->pc_delay); +} + +__or_dynop void op_clear_delay_insn(void) +{ + env->delay_insn = 0; +} + +__or_dynop void op_set_delay_insn(void) +{ + env->delay_insn = 1; +} + +__or_dynop void op_check_delay_slot(void) +{ + if(!env->delay_insn) + OP_JUMP(OP_PARAM1); +} + +__or_dynop void op_jmp_imm(void) +{ + OP_JUMP(OP_PARAM1); +} + +__or_dynop void op_set_flag(void) +{ + env->sprs[SPR_SR] |= SPR_SR_F; +} + +__or_dynop void op_clear_flag(void) +{ + env->sprs[SPR_SR] &= ~SPR_SR_F; +} + +/* Used for the l.bf instruction. Therefore if the flag is not set, jump over + * all the jumping stuff */ +__or_dynop void op_check_flag(void) +{ + if(!(env->sprs[SPR_SR] & SPR_SR_F)) { + HANDLE_SCHED(do_sched_wrap, "no_sched_chk_flg"); + OP_JUMP(OP_PARAM1); + } +} + +/* Used for l.bf if the delay slot instruction is on another page */ +__or_dynop void op_check_flag_delay(void) +{ + if(env->sprs[SPR_SR] & SPR_SR_F) { + env->delay_insn = 1; + env->pc_delay = get_pc() + (orreg_t)OP_PARAM1; + } +} + +/* Used for the l.bnf instruction. Therefore if the flag is set, jump over all + * the jumping stuff */ +__or_dynop void op_check_not_flag(void) +{ + if(env->sprs[SPR_SR] & SPR_SR_F) { + HANDLE_SCHED(do_sched_wrap, "no_sched_chk_not_flg"); + OP_JUMP(OP_PARAM1); + } +} + +/* Used for l.bnf if the delay slot instruction is on another page */ +__or_dynop void op_check_not_flag_delay(void) +{ + if(!(env->sprs[SPR_SR] & SPR_SR_F)) { + env->delay_insn = 1; + env->pc_delay = get_pc() + (orreg_t)OP_PARAM1; + } +} + +__or_dynop void op_set_ts_current(void) +{ + env->ts_current = 1; +} + +__or_dynop void op_add_pc(void) +{ + /* FIXME: Optimise */ + set_pc(get_pc() + OP_PARAM1); +} + +__or_dynop void op_nop_exit(void) +{ + upd_sim_cycles(); + save_t_temporary(); + op_support_nop_exit(); + FORCE_RET; +} + +__or_dynop void op_nop_reset(void) +{ + upd_sim_cycles(); + op_support_nop_reset(); + do_jump(EXCEPT_RESET); +} + +__or_dynop void op_nop_printf(void) +{ + save_t_temporary(); + upd_sim_cycles(); + op_support_nop_printf(); + FORCE_RET; +} + +__or_dynop void op_nop_report(void) +{ + save_t_temporary(); + upd_sim_cycles(); + op_support_nop_report(); + FORCE_RET; +} + +__or_dynop void op_nop_report_imm(void) +{ + save_t_temporary(); + upd_sim_cycles(); + op_support_nop_report_imm(OP_PARAM1); +} + +__or_dynop void op_check_null_except_t0_delay(void) +{ + if(!t0) { + /* Do exception */ + env->sprs[SPR_EEAR_BASE] = get_pc() - 4; + env->delay_insn = 0; + do_jump(EXCEPT_ILLEGAL); + } +} + + +__or_dynop void op_check_null_except_t0(void) +{ + if(!t0) { + /* Do exception */ + env->sprs[SPR_EEAR_BASE] = get_pc(); + do_jump(EXCEPT_ILLEGAL); + } +} + +__or_dynop void op_check_null_except_t1_delay(void) +{ + if(!t1) { + /* Do exception */ + env->sprs[SPR_EEAR_BASE] = get_pc() - 4; + env->delay_insn = 0; + do_jump(EXCEPT_ILLEGAL); + } +} + + +__or_dynop void op_check_null_except_t1(void) +{ + if(!t1) { + /* Do exception */ + env->sprs[SPR_EEAR_BASE] = get_pc(); + do_jump(EXCEPT_ILLEGAL); + } +} + +__or_dynop void op_check_null_except_t2_delay(void) +{ + if(!t2) { + /* Do exception */ + env->sprs[SPR_EEAR_BASE] = get_pc() - 4; + env->delay_insn = 0; + do_jump(EXCEPT_ILLEGAL); + } +} + +__or_dynop void op_check_null_except_t2(void) +{ + if(!t2) { + /* Do exception */ + env->sprs[SPR_EEAR_BASE] = get_pc(); + do_jump(EXCEPT_ILLEGAL); + } +} + +__or_dynop void op_analysis(void) +{ + env->iqueue.insn_index = OP_PARAM1; + env->iqueue.insn = OP_PARAM2; + env->iqueue.insn_addr = get_pc(); + save_t_temporary(); + op_support_analysis(); + FORCE_RET; +} + +#define OP_EXTRA + +#define OP / +#define OP_CAST(T) (orreg_t)T +#define OP_NAME div +#include "op_arith_op.h" +#undef OP_NAME +#undef OP_CAST +#undef OP + +#define OP / +#define OP_CAST(T) T +#define OP_NAME divu +#include "op_arith_op.h" +#undef OP_NAME +#undef OP_CAST +#undef OP + +#define OP * +#define OP_CAST(T) T +#define OP_NAME mulu +#include "op_arith_op.h" +#undef OP_NAME +#undef OP_CAST +#undef OP + +#define OP - +#define OP_CAST(T) (orreg_t)T +#define OP_NAME sub +#include "op_arith_op.h" +#undef OP_NAME +#undef OP_CAST +#undef OP + +#undef OP_EXTRA + +#define OP_HAS_IMM + +#define OP_EXTRA + ((env->sprs[SPR_SR] & SPR_SR_CY) >> 10) +#define OP + +#define OP_CAST(T) (orreg_t)T +#define OP_NAME addc +#include "op_arith_op.h" +#undef OP_NAME +#undef OP_CAST +#undef OP + +#undef OP_EXTRA +#define OP_EXTRA + +#define OP + +#define OP_CAST(T) (orreg_t)T +#define OP_NAME add +#include "op_arith_op.h" +#undef OP_NAME +#undef OP_CAST +#undef OP + +#define OP & +#define OP_CAST(T) T +#define OP_NAME and +#include "op_arith_op.h" +#undef OP_NAME +#undef OP_CAST +#undef OP + +#define OP * +#define OP_CAST(T) (orreg_t)T +#define OP_NAME mul +#include "op_arith_op.h" +#undef OP_NAME +#undef OP_CAST +#undef OP + +#define OP | +#define OP_CAST(T) T +#define OP_NAME or +#include "op_arith_op.h" +#undef OP_NAME +#undef OP_CAST +#undef OP + +#define OP << +#define OP_CAST(T) T +#define OP_NAME sll +#include "op_arith_op.h" +#undef OP_NAME +#undef OP_CAST +#undef OP + +#define OP >> +#define OP_CAST(T) (orreg_t)T +#define OP_NAME sra +#include "op_arith_op.h" +#undef OP_NAME +#undef OP_CAST +#undef OP + +#define OP >> +#define OP_CAST(T) T +#define OP_NAME srl +#include "op_arith_op.h" +#undef OP_NAME +#undef OP_CAST +#undef OP + +#define OP ^ +#define OP_CAST(T) T +#define OP_NAME xor +#include "op_arith_op.h" +#undef OP_NAME +#undef OP_CAST +#undef OP + +#undef OP_EXTRA +#undef OP_HAS_IMM + +#define EXT_NAME extbs +#define EXT_TYPE int8_t +#define EXT_CAST (orreg_t) +#include "op_extend_op.h" +#undef EXT_CAST +#undef EXT_TYPE +#undef EXT_NAME + +#define EXT_NAME extbz +#define EXT_TYPE uint8_t +#define EXT_CAST (uorreg_t) +#include "op_extend_op.h" +#undef EXT_CAST +#undef EXT_TYPE +#undef EXT_NAME + +#define EXT_NAME exths +#define EXT_TYPE int16_t +#define EXT_CAST (orreg_t) +#include "op_extend_op.h" +#undef EXT_CAST +#undef EXT_TYPE +#undef EXT_NAME + +#define EXT_NAME exthz +#define EXT_TYPE uint16_t +#define EXT_CAST (uorreg_t) +#include "op_extend_op.h" +#undef EXT_CAST +#undef EXT_TYPE +#undef EXT_NAME + +#define COMP == +#define COMP_NAME sfeq +#define COMP_CAST(t) t +#include "op_comp_op.h" +#undef COMP_CAST +#undef COMP_NAME +#undef COMP + +#define COMP != +#define COMP_NAME sfne +#define COMP_CAST(t) t +#include "op_comp_op.h" +#undef COMP_CAST +#undef COMP_NAME +#undef COMP + +#define COMP > +#define COMP_NAME sfgtu +#define COMP_CAST(t) t +#include "op_comp_op.h" +#undef COMP_CAST +#undef COMP_NAME +#undef COMP + +#define COMP >= +#define COMP_NAME sfgeu +#define COMP_CAST(t) t +#include "op_comp_op.h" +#undef COMP_CAST +#undef COMP_NAME +#undef COMP + +#define COMP < +#define COMP_NAME sfltu +#define COMP_CAST(t) t +#include "op_comp_op.h" +#undef COMP_CAST +#undef COMP_NAME +#undef COMP + +#define COMP <= +#define COMP_NAME sfleu +#define COMP_CAST(t) t +#include "op_comp_op.h" +#undef COMP_CAST +#undef COMP_NAME +#undef COMP + +#define COMP > +#define COMP_NAME sfgts +#define COMP_CAST(t) (orreg_t)t +#include "op_comp_op.h" +#undef COMP_CAST +#undef COMP_NAME +#undef COMP + +#define COMP >= +#define COMP_NAME sfges +#define COMP_CAST(t) (orreg_t)t +#include "op_comp_op.h" +#undef COMP_CAST +#undef COMP_NAME +#undef COMP + +#define COMP < +#define COMP_NAME sflts +#define COMP_CAST(t) (orreg_t)t +#include "op_comp_op.h" +#undef COMP_CAST +#undef COMP_NAME +#undef COMP + +#define COMP <= +#define COMP_NAME sfles +#define COMP_CAST(t) (orreg_t)t +#include "op_comp_op.h" +#undef COMP_CAST +#undef COMP_NAME +#undef COMP + +#define REG 1 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 2 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 3 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 4 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 5 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 6 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 7 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 8 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 9 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 10 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 11 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 12 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 13 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 14 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 15 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 16 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 17 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 18 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 19 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 20 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 21 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 22 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 23 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 24 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 25 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 26 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 27 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 28 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 29 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 30 +#include "op_t_reg_mov_op.h" +#undef REG + +#define REG 31 +#include "op_t_reg_mov_op.h" +#undef REG + +#define DST_T t0 +#define SRC_T t0 +#include "op_ff1_op.h" +#undef SRC_T + +#define SRC_T t1 +#include "op_ff1_op.h" +#undef SRC_T + +#define SRC_T t2 +#include "op_ff1_op.h" +#undef SRC_T +#undef DST_T + +#define DST_T t1 +#define SRC_T t0 +#include "op_ff1_op.h" +#undef SRC_T + +#define SRC_T t1 +#include "op_ff1_op.h" +#undef SRC_T + +#define SRC_T t2 +#include "op_ff1_op.h" +#undef SRC_T +#undef DST_T + +#define DST_T t2 +#define SRC_T t0 +#include "op_ff1_op.h" +#undef SRC_T + +#define SRC_T t1 +#include "op_ff1_op.h" +#undef SRC_T + +#define SRC_T t2 +#include "op_ff1_op.h" +#undef SRC_T +#undef DST_T + +#define SPR_T_NAME SPR_T +#define GPR_T_NAME GPR_T + +#define SPR_T t0 +#define GPR_T t0 +#include "op_mftspr_op.h" +#undef GPR_T + +#define GPR_T t1 +#include "op_mftspr_op.h" +#undef GPR_T + +#define GPR_T t2 +#include "op_mftspr_op.h" +#undef GPR_T +#undef SPR_T + +#define SPR_T t1 +#define GPR_T t0 +#include "op_mftspr_op.h" +#undef GPR_T + +#define GPR_T t1 +#include "op_mftspr_op.h" +#undef GPR_T + +#define GPR_T t2 +#include "op_mftspr_op.h" +#undef GPR_T +#undef SPR_T + +#define SPR_T t2 +#define GPR_T t0 +#include "op_mftspr_op.h" +#undef GPR_T + +#define GPR_T t1 +#include "op_mftspr_op.h" +#undef GPR_T + +#define GPR_T t2 +#include "op_mftspr_op.h" +#undef GPR_T +#undef SPR_T + +#undef GPR_T_NAME +#undef SPR_T_NAME + +#define SPR_T_NAME imm +#define GPR_T_NAME GPR_T + +#define SPR_T 0 + +#define GPR_T t0 +#include "op_mftspr_op.h" +#undef GPR_T + +#define GPR_T t1 +#include "op_mftspr_op.h" +#undef GPR_T + +#define GPR_T t2 +#include "op_mftspr_op.h" +#undef GPR_T +#undef SPR_T + +#undef SPR_T_NAME +#undef GPR_T_NAME + +#define ONLY_MTSPR +#define SPR_T_NAME SPR_T +#define GPR_T_NAME clear + +#define GPR_T 0 + +#define SPR_T t0 +#include "op_mftspr_op.h" +#undef SPR_T + +#define SPR_T t1 +#include "op_mftspr_op.h" +#undef SPR_T + +#define SPR_T t2 +#include "op_mftspr_op.h" +#undef SPR_T + +#undef GPR_T + +#undef SPR_T_NAME +#undef GPR_T_NAME + +#define SPR_T_NAME imm +#define GPR_T_NAME clear +#define GPR_T 0 +#define SPR_T 0 +#include "op_mftspr_op.h" +#undef SPR_T +#undef GPR_T +#undef GPR_T_NAME +#undef SPR_T_NAME + +#undef ONLY_MTSPR + +#define OP += +#define OP_NAME mac +#include "op_mac_op.h" +#undef OP_NAME +#undef OP + +#define OP -= +#define OP_NAME msb +#include "op_mac_op.h" +#undef OP_NAME +#undef OP + +#define LS_OP_NAME lbz +#define LS_OP_CAST +#define LS_OP_FUNC eval_mem8 +#include "op_lwhb_op.h" +#undef LS_OP_FUNC +#undef LS_OP_CAST +#undef LS_OP_NAME + +#define LS_OP_NAME lbs +#define LS_OP_CAST (int8_t) +#define LS_OP_FUNC eval_mem8 +#include "op_lwhb_op.h" +#undef LS_OP_FUNC +#undef LS_OP_CAST +#undef LS_OP_NAME + +#define LS_OP_NAME lhz +#define LS_OP_CAST +#define LS_OP_FUNC eval_mem16 +#include "op_lwhb_op.h" +#undef LS_OP_FUNC +#undef LS_OP_CAST +#undef LS_OP_NAME + +#define LS_OP_NAME lhs +#define LS_OP_CAST (int16_t) +#define LS_OP_FUNC eval_mem16 +#include "op_lwhb_op.h" +#undef LS_OP_FUNC +#undef LS_OP_CAST +#undef LS_OP_NAME + +#define LS_OP_NAME lwz +#define LS_OP_CAST +#define LS_OP_FUNC eval_mem32 +#include "op_lwhb_op.h" +#undef LS_OP_FUNC +#undef LS_OP_CAST +#undef LS_OP_NAME + +#define LS_OP_NAME lws +#define LS_OP_CAST (int32_t) +#define LS_OP_FUNC eval_mem32 +#include "op_lwhb_op.h" +#undef LS_OP_FUNC +#undef LS_OP_CAST +#undef LS_OP_NAME + +#define S_OP_NAME sb +#define S_FUNC set_mem8 +#include "op_swhb_op.h" +#undef S_FUNC +#undef S_OP_NAME + +#define S_OP_NAME sh +#define S_FUNC set_mem16 +#include "op_swhb_op.h" +#undef S_FUNC +#undef S_OP_NAME + +#define S_OP_NAME sw +#define S_FUNC set_mem32 +#include "op_swhb_op.h" +#undef S_FUNC +#undef S_OP_NAME + +__or_dynop void op_join_mem_cycles(void) +{ + join_mem_cycles(); +} + +__or_dynop void op_store_link_addr_gpr(void) +{ + env->reg[LINK_REGNO] = get_pc() + 8; +} + +__or_dynop void op_prep_rfe(void) +{ + env->sprs[SPR_SR] = env->sprs[SPR_ESR_BASE] | SPR_SR_FO; + env->sprs[SPR_PPC] = get_pc(); + env->ts_current = 1; + set_pc(env->sprs[SPR_EPCR_BASE] - 4); +} + +static inline void prep_except(oraddr_t epcr_base) +{ + env->sprs[SPR_EPCR_BASE] = epcr_base; + + env->sprs[SPR_ESR_BASE] = env->sprs[SPR_SR]; + + /* Address translation is always disabled when starting exception. */ + env->sprs[SPR_SR] &= ~SPR_SR_DME; + env->sprs[SPR_SR] &= ~SPR_SR_IME; + + env->sprs[SPR_SR] &= ~SPR_SR_OVE; /* Disable overflow flag exception. */ + + env->sprs[SPR_SR] |= SPR_SR_SM; /* SUPV mode */ + env->sprs[SPR_SR] &= ~(SPR_SR_IEE | SPR_SR_TEE); /* Disable interrupts. */ +} + +__or_dynop void op_set_except_pc(void) +{ + set_pc(OP_PARAM1); +} + +/* Before the code in op_{sys,trap}{,_delay} gets run, the scheduler runs. + * Therefore the pc will point to the instruction after the l.sys or l.trap + * instruction */ +__or_dynop void op_prep_sys_delay(void) +{ + env->delay_insn = 0; + env->ts_current = 1; + prep_except(get_pc() - 4); + set_pc(EXCEPT_SYSCALL - 4); +} + +__or_dynop void op_prep_sys(void) +{ + env->ts_current = 1; + prep_except(get_pc() + 4); + set_pc(EXCEPT_SYSCALL - 4); +} + +__or_dynop void op_prep_trap_delay(void) +{ + env->ts_current = 1; + env->delay_insn = 0; + prep_except(get_pc() - 4); + set_pc(EXCEPT_TRAP - 4); +} + +__or_dynop void op_prep_trap(void) +{ + env->ts_current = 1; + prep_except(get_pc()); + set_pc(EXCEPT_TRAP - 4); +} + +/* FIXME: This `instruction' should be split up like the l.trap and l.sys + * instructions are done */ +__or_dynop void op_illegal_delay(void) +{ + env->delay_insn = 0; + env->ts_current = 1; + env->sprs[SPR_EEAR_BASE] = get_pc() - 4; + do_jump(EXCEPT_ILLEGAL - 4); +} + +__or_dynop void op_illegal(void) +{ + env->sprs[SPR_EEAR_BASE] = get_pc(); + do_jump(EXCEPT_ILLEGAL); +} + +__or_dynop void op_do_sched(void) +{ + HANDLE_SCHED(do_sched_wrap, "no_sched"); +} + +__or_dynop void op_do_sched_delay(void) +{ + HANDLE_SCHED(do_sched_wrap_delay, "no_sched_delay"); +} + +__or_dynop void op_macc(void) +{ + env->sprs[SPR_MACLO] = 0; + env->sprs[SPR_MACHI] = 0; +} + +__or_dynop void op_store_insn_ea(void) +{ + env->insn_ea = OP_PARAM1; +} + +__or_dynop void op_calc_insn_ea_t0(void) +{ + env->insn_ea = t0 + OP_PARAM1; +} + +__or_dynop void op_calc_insn_ea_t1(void) +{ + env->insn_ea = t1 + OP_PARAM1; +} + +__or_dynop void op_calc_insn_ea_t2(void) +{ + env->insn_ea = t2 + OP_PARAM1; +} + +__or_dynop void op_macrc_t0(void) +{ + /* FIXME: How is this supposed to work? The architechture manual says that + * the low 32-bits shall be saved into rD. I have just copied this code from + * insnset.c to make testbench/mul pass */ + int64_t temp = env->sprs[SPR_MACLO] | ((int64_t)env->sprs[SPR_MACHI] << 32); + + t0 = (orreg_t)(temp >> 28); + env->sprs[SPR_MACLO] = 0; + env->sprs[SPR_MACHI] = 0; +} + +__or_dynop void op_macrc_t1(void) +{ + /* FIXME: How is this supposed to work? The architechture manual says that + * the low 32-bits shall be saved into rD. I have just copied this code from + * insnset.c to make testbench/mul pass */ + int64_t temp = env->sprs[SPR_MACLO] | ((int64_t)env->sprs[SPR_MACHI] << 32); + + t1 = (orreg_t)(temp >> 28); + + env->sprs[SPR_MACLO] = 0; + env->sprs[SPR_MACHI] = 0; +} + +__or_dynop void op_macrc_t2(void) +{ + /* FIXME: How is this supposed to work? The architechture manual says that + * the low 32-bits shall be saved into rD. I have just copied this code from + * insnset.c to make testbench/mul pass */ + int64_t temp = env->sprs[SPR_MACLO] | ((int64_t)env->sprs[SPR_MACHI] << 32); + + t2 = (orreg_t)(temp >> 28); + + env->sprs[SPR_MACLO] = 0; + env->sprs[SPR_MACHI] = 0; +} + +__or_dynop void op_mac_imm_t0(void) +{ + int64_t temp = env->sprs[SPR_MACLO] | ((int64_t)env->sprs[SPR_MACHI] << 32); + + temp += (int64_t)t0 * (int64_t)OP_PARAM1; + + env->sprs[SPR_MACLO] = temp & 0xffffffff; + env->sprs[SPR_MACHI] = temp >> 32; +} + +__or_dynop void op_mac_imm_t1(void) +{ + int64_t temp = env->sprs[SPR_MACLO] | ((int64_t)env->sprs[SPR_MACHI] << 32); + + temp += (int64_t)t1 * (int64_t)OP_PARAM1; + + env->sprs[SPR_MACLO] = temp & 0xffffffff; + env->sprs[SPR_MACHI] = temp >> 32; +} + +__or_dynop void op_mac_imm_t2(void) +{ + int64_t temp = env->sprs[SPR_MACLO] | ((int64_t)env->sprs[SPR_MACHI] << 32); + + temp += (int64_t)t2 * (int64_t)OP_PARAM1; + + env->sprs[SPR_MACLO] = temp & 0xffffffff; + env->sprs[SPR_MACHI] = temp >> 32; +} + +__or_dynop void op_cmov_t0_t0_t1(void) +{ + t0 = env->sprs[SPR_SR] & SPR_SR_F ? t0 : t1; +} + +__or_dynop void op_cmov_t0_t0_t2(void) +{ + t0 = env->sprs[SPR_SR] & SPR_SR_F ? t0 : t2; +} + +__or_dynop void op_cmov_t0_t1_t0(void) +{ + t0 = env->sprs[SPR_SR] & SPR_SR_F ? t1 : t0; +} + +__or_dynop void op_cmov_t0_t1_t2(void) +{ + t0 = env->sprs[SPR_SR] & SPR_SR_F ? t1 : t2; + FORCE_RET; +} + +__or_dynop void op_cmov_t0_t2_t0(void) +{ + t0 = env->sprs[SPR_SR] & SPR_SR_F ? t2 : t0; +} + +__or_dynop void op_cmov_t0_t2_t1(void) +{ + t0 = env->sprs[SPR_SR] & SPR_SR_F ? t2 : t1; + FORCE_RET; +} + +__or_dynop void op_cmov_t1_t0_t1(void) +{ + t1 = env->sprs[SPR_SR] & SPR_SR_F ? t0 : t1; +} + +__or_dynop void op_cmov_t1_t0_t2(void) +{ + t1 = env->sprs[SPR_SR] & SPR_SR_F ? t0 : t2; + FORCE_RET; +} + +__or_dynop void op_cmov_t1_t1_t0(void) +{ + t1 = env->sprs[SPR_SR] & SPR_SR_F ? t1 : t0; +} + +__or_dynop void op_cmov_t1_t1_t2(void) +{ + t1 = env->sprs[SPR_SR] & SPR_SR_F ? t1 : t2; +} + +__or_dynop void op_cmov_t1_t2_t0(void) +{ + t1 = env->sprs[SPR_SR] & SPR_SR_F ? t2 : t0; + FORCE_RET; +} + +__or_dynop void op_cmov_t1_t2_t1(void) +{ + t1 = env->sprs[SPR_SR] & SPR_SR_F ? t2 : t1; +} + +__or_dynop void op_cmov_t2_t0_t1(void) +{ + t2 = env->sprs[SPR_SR] & SPR_SR_F ? t0 : t1; + FORCE_RET; +} + +__or_dynop void op_cmov_t2_t0_t2(void) +{ + t2 = env->sprs[SPR_SR] & SPR_SR_F ? t0 : t2; +} + +__or_dynop void op_cmov_t2_t1_t0(void) +{ + t2 = env->sprs[SPR_SR] & SPR_SR_F ? t1 : t0; + FORCE_RET; +} + +__or_dynop void op_cmov_t2_t1_t2(void) +{ + t2 = env->sprs[SPR_SR] & SPR_SR_F ? t1 : t2; +} + +__or_dynop void op_cmov_t2_t2_t0(void) +{ + t2 = env->sprs[SPR_SR] & SPR_SR_F ? t2 : t0; +} + +__or_dynop void op_cmov_t2_t2_t1(void) +{ + t2 = env->sprs[SPR_SR] & SPR_SR_F ? t2 : t1; +} + +__or_dynop void op_neg_t0_t0(void) +{ + t0 = -t0; +} + +__or_dynop void op_neg_t0_t1(void) +{ + t0 = -t1; +} + +__or_dynop void op_neg_t0_t2(void) +{ + t0 = -t2; +} + +__or_dynop void op_neg_t1_t0(void) +{ + t1 = -t0; +} + +__or_dynop void op_neg_t1_t1(void) +{ + t1 = -t1; +} + +__or_dynop void op_neg_t1_t2(void) +{ + t1 = -t2; +} + +__or_dynop void op_neg_t2_t0(void) +{ + t2 = -t0; +} + +__or_dynop void op_neg_t2_t1(void) +{ + t2 = -t1; +} + +__or_dynop void op_neg_t2_t2(void) +{ + t2 = -t2; +} + Index: op_support.c =================================================================== --- op_support.c (nonexistent) +++ op_support.c (revision 1765) @@ -0,0 +1,207 @@ +/* op_support.c -- Support routines for micro operations + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include + +#include "config.h" + +#ifdef HAVE_INTTYPES_H +#include +#endif + +#include "port.h" +#include "arch.h" +#include "opcode/or32.h" +#include "sim-config.h" +#include "spr_defs.h" +#include "except.h" +#include "immu.h" +#include "abstract.h" +#include "execute.h" +#include "sched.h" + +#include "i386_regs.h" + +#include "dyn_rec.h" +#include "op_support.h" + +#include "rec_i386.h" + +/* Stuff that is really a `micro' operation but is rather big (or for some other + * reason like calling exit()) */ + +void upd_reg_from_t(oraddr_t pc, int bound) +{ + int reg; + + pc = ((pc & (PAGE_SIZE - 1)) / 4); + + if(bound) { + reg = cpu_state.curr_page->ts_bound[pc + 1]; + } else + reg = cpu_state.curr_page->ts_during[pc]; + + if(reg & 0x1f) + cpu_state.reg[reg & 0x1f] = cpu_state.t0; + + if((reg >> 5) & 0x1f) + cpu_state.reg[(reg >> 5) & 0x1f] = cpu_state.t1; + + if((reg >> 10) & 0x1f) + cpu_state.reg[(reg >> 10) & 0x1f] = cpu_state.t2; +} + +void op_support_nop_exit(void) +{ + upd_reg_from_t(get_pc(), 0); + PRINTF("exit(%"PRIdREG")\n", cpu_state.reg[3]); + fprintf(stderr, "@reset : cycles %lld, insn #%lld\n", + runtime.sim.reset_cycles, runtime.cpu.reset_instructions); + fprintf(stderr, "@exit : cycles %lld, insn #%lld\n", runtime.sim.cycles, + runtime.cpu.instructions); + fprintf(stderr, " diff : cycles %lld, insn #%lld\n", + runtime.sim.cycles - runtime.sim.reset_cycles, + runtime.cpu.instructions - runtime.cpu.reset_instructions); + /* FIXME: Implement emulation of a stalled cpu + if (config.debug.gdb_enabled) + set_stall_state (1); + else { + handle_sim_command(); + sim_done(); + } + */ + exit(0); +} + +void op_support_nop_reset(void) +{ + PRINTF("****************** counters reset ******************\n"); + PRINTF("cycles %lld, insn #%lld\n", runtime.sim.cycles, runtime.cpu.instructions); + PRINTF("****************** counters reset ******************\n"); + runtime.sim.reset_cycles = runtime.sim.cycles; + runtime.cpu.reset_instructions = runtime.cpu.instructions; +} + +void op_support_nop_printf(void) +{ + upd_reg_from_t(get_pc(), 0); + simprintf(cpu_state.reg[4], cpu_state.reg[3]); +} + +void op_support_nop_report(void) +{ + upd_reg_from_t(get_pc(), 0); + PRINTF("report(0x%"PRIxREG");\n", cpu_state.reg[3]); +} + +void op_support_nop_report_imm(int imm) +{ + upd_reg_from_t(get_pc(), 0); + PRINTF("report %i (0x%"PRIxREG");\n", imm, cpu_state.reg[3]); +} + +/* Handles a jump */ +/* addr is a VIRTUAL address */ +/* NOTE: We can't use env since this code is compiled like the rest of the + * simulator (most likely without -fomit-frame-pointer) and thus env will point + * to some bogus value. */ +void do_jump(oraddr_t addr) +{ + struct dyn_page *target_dp; + oraddr_t phys_page; + + /* Temporaries are always shipped out */ + cpu_state.ts_current = 1; + + /* The pc is set to the location of the jump in op_set_pc_preemt(_check) and + * then it is incermented by 4 when the scheduler is run. If a scheduled job + * so happens to raise an exception cpu_state.delay_insn will still be set and + * so except_handle will do its pc adjusting magic (ie. -4 from it) and every- + * thing ends up just working right, except when a scheduled job does not + * raise an exeception. In that case we set the pc here explicitly */ + set_pc(addr); + + /* immu_translate must be called after set_pc. If it would be called before + * it and it issued an ITLB miss then it would appear that the instruction + * that faulted was the instruction in the delay slot which is incorrect */ + phys_page = immu_translate(addr); + + /* do_jump is called from the delay slot, which is the jump instruction + * address + 4. */ +/* + printf("Recompiled code jumping out to %"PRIxADDR" from %"PRIxADDR"\n", + phys_page, cpu_state.sprs[SPR_PPC] - 4); +*/ + + /* immu_translate() adds the hit delay to runtime.sim.mem_cycles but we add it + * to the cycles when the instruction is executed so if we don't reset it now + * it will produce wrong results */ + runtime.sim.mem_cycles = 0; + + target_dp = cpu_state.dyn_pages[phys_page >> config.immu.pagesize_log2]; + + if(!target_dp) + target_dp = new_dp(phys_page); + + /* Since writes to the 0x0-0xff range do not dirtyfy a page recompile the 0x0 + * page if the jump is to that location */ + if(phys_page < 0x100) + target_dp->dirty = 1; + + if(target_dp->dirty) + recompile_page(target_dp); + + cpu_state.curr_page = target_dp; + + /* FIXME: If the page is backed by more than one type of memory, this will + * produce wrong results */ + if(cpu_state.sprs[SPR_SR] & SPR_SR_IME) + /* Add the mmu hit delay to the cycle counter */ + upd_cycles_dec(target_dp->delayr - config.immu.hitdelay); + else + upd_cycles_dec(target_dp->delayr); + + cpu_state.ts_current = 0; + + /* Initially this returned the address that we should jump to and then the + * recompiled code performed the jump. This was no problem if the jump was + * trully an interpage jump or if the location didn't need recompileation. If + * the jump is page local and the page needs recompileation there is a very + * high probability that the page will move in memory and then the return + * address that is on the stack will point to memory that has already been + * freed, sometimes leading to crashes */ + /* This looks like it could really be simpler, but no it can't. The only + * issue here is the stack: it has to be unwound. This function is called + * from except_handle, which generally ends up quite high on the stack... */ + enter_dyn_code(phys_page, target_dp); +} + +/* Wrapper around analysis() that contains all the recompiler specific stuff */ +void op_support_analysis(void) +{ + upd_sim_cycles(); + if(IADDR_PAGE(cpu_state.pc) != cpu_state.pc) + upd_reg_from_t(cpu_state.pc - (cpu_state.delay_insn ? 4 : 0), 0); + else + upd_reg_from_t(cpu_state.pc, 0); + runtime.cpu.instructions++; + analysis(&cpu_state.iqueue); +} + Index: dyn_rec.h =================================================================== --- dyn_rec.h (nonexistent) +++ dyn_rec.h (revision 1765) @@ -0,0 +1,56 @@ +/* dyn_rec.h -- Recompiler specific definitions + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#ifndef DYN_REC_H +#define DYN_REC_H + +/* Each dynamically recompiled page has one of these */ +struct dyn_page { + oraddr_t or_page; + void *host_page; + unsigned int host_len; + int dirty; /* Is recompiled page invalid? */ + int delayr; /* delayr of memory backing this page */ + uint16_t ts_during[2048]; /* What registers the temporaries back (during the + * instruction) */ + uint16_t ts_bound[2049]; /* What registers the temporaries back (on the + * begining boundry of the instruction) */ + void **locs; /* Openrisc locations in the recompiled code */ +}; + +void recompile_page(struct dyn_page *dyn); +struct dyn_page *new_dp(oraddr_t page); +void add_to_opq(struct op_queue *opq, int end, int op); +void add_to_op_params(struct op_queue *opq, int end, unsigned long param); +void *enough_host_page(struct dyn_page *dp, void *cur, unsigned int *len, + unsigned int amount); +void init_dyn_recomp(void); +void jump_dyn_code(oraddr_t addr); +void run_sched_out_of_line(int add_normal); +void recheck_immu(int got_en_dis); +void enter_dyn_code(oraddr_t addr, struct dyn_page *dp); +void dyn_checkwrite(oraddr_t addr); + +extern void *rec_stack_base; + +#define IMMU_GOT_ENABLED 1 +#define IMMU_GOT_DISABLED 2 + +#endif Index: Makefile.am =================================================================== --- Makefile.am (nonexistent) +++ Makefile.am (revision 1765) @@ -0,0 +1,69 @@ +# Makefile -- Makefile for OR32 dependent simulation +# Copyright (C) 1999 Damjan Lampret, lampret@opencores.org +# +# This file is part of OpenRISC 1000 Architectural Simulator. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +noinst_LIBRARIES = libarch.a + +if DYNAMIC_EXECUTION + +noinst_PROGRAMS = dyngen test_dyn_rec +test_dyn_rec_SOURCES = op.c dyn_rec.c op_support.c gen_ops.c gen_ops_gen.c gen_ops_rel.c dyn_rec_stubs.c or32.c + +dyngen_SOURCES = dyngen.c dyngen_i386.c dyngen_elf.c + +libarch_a_SOURCES = execute.c or32.c op.c dyn_rec.c op_support.c gen_ops.c gen_ops_gen.c gen_ops_rel.c + +dyn_rec.o: gen_ops.h + +OP_CFLAGS=-Wall -fomit-frame-pointer -fno-reorder-blocks -O2 + +op.S: op.c op_t_reg_mov_op.h op_i386.h op_arith_op.h op_comp_op.h op_extend_op.h op_ff1_op.h op_mac_op.h op_mftspr_op.h op_lwhb_op.h op_swhb_op.h + $(CC) $(INCLUDES) $(OP_CFLAGS) -o $@ -S $< + +gen_ops.h gen_ops.c gen_ops_gen.c gen_ops_rel.c: dyngen op.o + +op.o: op.c op_t_reg_mov_op.h op_i386.h op_arith_op.h op_comp_op.h op_extend_op.h op_ff1_op.h op_mac_op.h op_mftspr_op.h op_lwhb_op.h op_swhb_op.h + $(CC) $(INCLUDES) $(OP_CFLAGS) -o $@ -c $< + +gen_ops.h gen_ops.c gen_ops_gen.c gen_ops_rel.c: dyngen$(EXEEXT) op.o + ./dyngen$(EXEEXT) op.o gen_ops.c gen_ops_gen.c gen_ops_rel.c gen_ops.h + +else + +libarch_a_SOURCES = execute.c or32.c + +if GENERATE_NEEDED +noinst_PROGRAMS = generate +generate_SOURCES = or32.c generate.c + +BUILT_SOURCES = execgen.c + +execgen.c: generate$(EXEEXT) $(srcdir)/insnset.c + ./generate$(EXEEXT) $(srcdir)/insnset.c execgen.c + +else + +noinst_PROGRAMS = + +endif +endif + +# If the simulator was first built without --enable-simple and then with it, +# then also remove these two files +CLEANFILES=execgen.c generate gen_ops.c gen_ops.h gen_ops_rel.c gen_ops_gen.c Index: op_support.h =================================================================== --- op_support.h (nonexistent) +++ op_support.h (revision 1765) @@ -0,0 +1,28 @@ +/* op_support.h -- Definitions of support routines for operations + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +void op_support_nop_exit(void); +void op_support_nop_reset(void); +void op_support_nop_printf(void); +void op_support_nop_report(void); +void op_support_nop_report_imm(int imm); +void op_support_analysis(void); +void do_jump(oraddr_t addr); + +void upd_reg_from_t(oraddr_t pc, int bound); Index: op_t_reg_mov_op.h =================================================================== --- op_t_reg_mov_op.h (nonexistent) +++ op_t_reg_mov_op.h (revision 1765) @@ -0,0 +1,56 @@ +/* op_t_reg_mov_op.h -- Micro operations template for reg->temporary operations + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +__or_dynop void glue(op_move_t0_gpr, REG)(void) +{ + t0 = env->reg[REG]; +} + +__or_dynop void glue(op_move_t1_gpr, REG)(void) +{ + t1 = env->reg[REG]; +} + +__or_dynop void glue(op_move_t2_gpr, REG)(void) +{ + t2 = env->reg[REG]; +} + +__or_dynop void glue(glue(op_move_gpr, REG), _t0)(void) +{ + env->reg[REG] = t0; +} + +__or_dynop void glue(glue(op_move_gpr, REG), _t1)(void) +{ + env->reg[REG] = t1; +} + +__or_dynop void glue(glue(op_move_gpr, REG), _t2)(void) +{ + env->reg[REG] = t2; +} + +__or_dynop void glue(glue(op_move_gpr, REG), _pc_delay)(void) +{ + env->pc_delay = env->reg[REG]; + env->delay_insn = 1; +} + Index: dyngen.c =================================================================== --- dyngen.c (nonexistent) +++ dyngen.c (revision 1765) @@ -0,0 +1,289 @@ +/* dyngen.c -- Generates micro operation generating functions + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include +#include +#include + +#include "dyngen.h" + +#define OP_FUNC_PREFIX "op_" +#define OP_FUNC_PARAM_PREFIX "__op_param" +/* Have to add to to make sure that the param[] is 0 */ +#define MAX_PARAMS (3 + 1) + +static const char *c_file_head = +"#include \"config.h\"\n" +"\n" +"#include \n" +"\n" +"#include \"arch.h\"\n" +"#include \"opcode/or32.h\"\n" +"#include \"spr_defs.h\"\n" +"#include \"i386_regs.h\"\n" +"#include \"abstract.h\"\n" +"\n" +"#include \"dyn_rec.h\"\n" +"#include \"%s\"\n" +"\n"; + +static const char *gen_code_proto = +"void gen_code(struct op_queue *opq, struct dyn_page *dp);\n" +"void patch_relocs(struct op_queue *opq, void *host_page);\n" +"\n" +"#define op_mark_loc_indx 0\n" +"\n"; + +static const char *c_sw_file_head = +"#include \n" +"#include \n" +"\n" +"#include \"config.h\"\n" +"\n" +"#include \n" +"\n" +"#include \"arch.h\"\n" +"#include \"opcode/or32.h\"\n" +"#include \"spr_defs.h\"\n" +"#include \"i386_regs.h\"\n" +"#include \"abstract.h\"\n" +"#include \"dyn_rec.h\"\n" +"#include \"%s\"\n" +"\n" +"void gen_code(struct op_queue *opq, struct dyn_page *dp)\n" +"{\n" +" unsigned int *ops, i;\n" +" unsigned int host_len = dp->host_len;\n" +" void *host_cur = dp->host_page;\n" +" oraddr_t pc = dp->or_page;\n" +" void **loc = dp->locs;\n" +"\n" +" while(opq) {\n" +" if(opq->next)\n" +" *loc++ = (void *)(host_cur - dp->host_page);" +"\n" +" for(i = 0, ops = opq->ops; i < opq->num_ops; i++, ops++) {\n" +" switch(*ops) {\n" +" case op_mark_loc_indx:\n" +" opq->ops_param[0] = host_cur - dp->host_page;\n" +" break;\n"; + +static const char *c_sw_file_tail = +" }\n" +" }\n" +" opq = opq->next;\n" +" pc += 4;\n" +" }\n" +"\n" +" dp->host_len = host_cur - dp->host_page;\n" +" dp->host_page = realloc(dp->host_page, dp->host_len);\n" +"}\n"; + +static const char *c_rel_file_head = +"#include /* To get printf... */\n" +"#include \n" +"\n" +"#include \"config.h\"\n" +"\n" +"#include \n" +"\n" +"#include \"arch.h\"\n" +"#include \"spr_defs.h\"\n" +"#include \"i386_regs.h\"\n" +"#include \"opcode/or32.h\"\n" +"#include \"abstract.h\"\n" +"#include \"tick.h\"\n" +"#include \"execute.h\"\n" +"#include \"sprs.h\"\n" +"#include \"dyn_rec.h\"\n" +"#include \"op_support.h\"\n" +"#include \"%s\"\n" +"\n" +"void do_scheduler(void); /* FIXME: Remove */\n" +"void do_sched_wrap(void); /* FIXME: Remove */\n" +"void do_sched_wrap_delay(void); /* FIXME: Remove */\n" +"void simprintf(oraddr_t stackaddr, unsigned long regparam); /* FIXME: Remove */\n" +"\n" +"void patch_relocs(struct op_queue *opq, void *host_page)\n" +"{\n" +" unsigned int *ops, *ops_param, i;\n" +"\n" +" while(opq) {\n" +" for(i = 0, ops = opq->ops, ops_param = opq->ops_param; i < opq->num_ops; i++, ops++) {\n" +" switch(*ops) {\n"; + +static const char *c_rel_file_tail = +" }\n" +" }\n" +" opq = opq->next;\n" +" }\n" +"}\n"; + +static void gen_func_proto(FILE *f, const char *name, int *params) +{ + int i; + + fprintf(f, "void gen_%s(struct op_queue *opq, int end", name); + for(i = 0; (i < MAX_PARAMS) && params[i]; i++) { + fprintf(f, ", uorreg_t param%i", i + 1); + } + fprintf(f, ")"); +} + +int main(int argc, char **argv) +{ + void *obj; + int i, j; + unsigned int len; + char *name; + int params[MAX_PARAMS]; + struct reloc reloc; + + FILE *c_file; + FILE *h_file; + FILE *c_sw_file; + FILE *c_rel_file; + + if(argc != 6) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + + obj = bffs.open_obj(argv[1]); + if(!obj) { + fprintf(stderr, "Unable to open object file %s\n", argv[1]); + return 1; + } + + if(!(c_file = fopen(argv[2], "w"))) { + fprintf(stderr, "Unable to open %s for writting\n", argv[2]); + bffs.close_obj(obj); + return 1; + } + + if(!(c_sw_file = fopen(argv[3], "w"))) { + fprintf(stderr, "Unable to open %s for writting\n", argv[2]); + fclose(c_file); + bffs.close_obj(obj); + } + + if(!(c_rel_file = fopen(argv[4], "w"))) { + fprintf(stderr, "Unable to open %s for writting\n", argv[3]); + fclose(c_file); + fclose(c_sw_file); + bffs.close_obj(obj); + return 1; + } + + if(!(h_file = fopen(argv[5], "w"))) { + fprintf(stderr, "Unable to open %s for writting\n", argv[3]); + fclose(c_file); + fclose(c_sw_file); + fclose(c_rel_file); + bffs.close_obj(obj); + return 1; + } + + fprintf(c_file, c_file_head, argv[5]); + fprintf(c_sw_file, c_sw_file_head, argv[5]); + fprintf(c_rel_file, c_rel_file_head, argv[5]); + fprintf(h_file, "%s", gen_code_proto); + + /* Itterate through the functions in the object file */ + for(i = 0; (name = bffs.get_func_name(obj, i)); i++) { + if(strncmp(name, OP_FUNC_PREFIX, strlen(OP_FUNC_PREFIX))) + continue; + + /* Find all the relocations associated with this function */ + memset(params, 0, sizeof(params)); + for(j = 0; bffs.get_func_reloc(obj, i, j, &reloc); j++) { + //fprintf(stderr, "%s %i %i\n", reloc.name, reloc.func_offset, reloc.addend); + if(strncmp(reloc.name, OP_FUNC_PARAM_PREFIX, strlen(OP_FUNC_PARAM_PREFIX))) { + continue; + } + params[atoi(reloc.name + strlen(OP_FUNC_PARAM_PREFIX)) - 1] = 1; + } + + len = archfs.get_real_func_len(bffs.get_func_start(obj, i), + bffs.get_func_len(obj, i), name); + + gen_func_proto(h_file, name, params); + fprintf(h_file, ";\n"); + + if(len) { + /* Prototype the operation */ + fprintf(h_file, "void %s(void);\n", name); + fprintf(h_file, "#define %s_indx %i\n", name, i); + } + + gen_func_proto(c_file, name, params); + fprintf(c_file, "\n{\n"); + if(len) { + fprintf(c_file, " add_to_opq(opq, end, %s_indx);\n", name); + + for(j = 0; params[j]; j++) + fprintf(c_file, " add_to_op_params(opq, end, param%i);\n", j + 1); + } + fprintf(c_file, "}\n\n"); + + if(!len) { + /* If the operation is of length 0, then just ignore it */ + fprintf(stderr, "WARNING: Useless operation (size == 0): %s\n", name); + continue; + } + + fprintf(c_sw_file, " case %s_indx:\n", name); + fprintf(c_sw_file, " host_cur = enough_host_page(dp, host_cur, &host_len, %i);\n", len); + fprintf(c_sw_file, " memcpy(host_cur, %s, %i);\n", name, len); + + fprintf(c_rel_file, " case %s_indx:\n", name); + for(j = 0; bffs.get_func_reloc(obj, i, j, &reloc); j++) { + /* Ignore nameless relocations, they appear to be absolute */ + if(!*reloc.name) + continue; + if(strncmp(reloc.name, OP_FUNC_PARAM_PREFIX, strlen(OP_FUNC_PARAM_PREFIX))) { + /* We have to manually do the relocations when the relocation is + * relative to the PC as the code gets copied to a different location + * during recompilation, where the relative addresses shall be waay out. + */ + archfs.gen_func_reloc(c_rel_file, &reloc); + } else { + archfs.gen_reloc(c_rel_file, &reloc, + atoi(reloc.name + strlen(OP_FUNC_PARAM_PREFIX))); + } + } + + fprintf(c_sw_file, " host_cur += %i;\n break;\n\n", len); + fprintf(c_rel_file, " host_page += %i;\n", len); + /* Count how many parameters where used */ + for(j = 0; params[j]; j++); + fprintf(c_rel_file, " ops_param += %i;\n break;\n\n", j); + } + + fprintf(c_sw_file, "%s", c_sw_file_tail); + fprintf(c_rel_file, "%s", c_rel_file_tail); + + fclose(h_file); + fclose(c_file); + fclose(c_sw_file); + fclose(c_rel_file); + bffs.close_obj(obj); + return 0; +} Index: rec_i386.h =================================================================== --- rec_i386.h (nonexistent) +++ rec_i386.h (revision 1765) @@ -0,0 +1,73 @@ +/* rec_i386.h -- i386 specific parts of the recompile engine + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include "common_i386.h" + +/* Initialises the recompiler (architechture specific). */ +static inline void init_dyn_rec(void) +{ + uint64_t add = UINT32_C(-1) | UINT64_C(4) << 32; + + /* Initialises the scheduler handling for future use. Because the x86 has a + * very low number of registers (8), I have to use MMX registers. I could do + * load/store combination but that takes up space and is slow. I use packed + * doublewords to strut my stuff. The high 32-bits of the first MMX register + * is the PC, the low 32-bits is the number of cycles that are still + * outstanding for the next scheduled job to run. The second MMX register + * holds the amount that needs to be added to the two values on each cycle. + * The third MMX register only holds the value that we must use to update the + * low 32-bits with */ + asm volatile ("movq %0, %%mm1\n" + : : "m" (add)); +} + +/* Gets the current stack pointer */ +static inline void *get_sp(void) +{ + void *stack; + asm("movl %%esp, %0" : "=rm" (stack)); + return stack; +} + +/* Updates the number of cycles that it takes to load 1 instruction */ +static inline void upd_cycles_dec(int32_t amount) +{ + useless_x86.val3232.high32 = 4; + useless_x86.val3232.low32 = amount; + asm volatile ("movq %0, %%mm1" : : "m" (useless_x86.val64)); +} + +/* Adds the number of cycles to the next job that would be added anyway */ +static inline void sched_add_cycles(void) +{ + asm("movd %%mm1, %%eax\n" + "\tmovd %%eax, %%mm2\n" + "paddd %%mm2, %%mm0" + : : : "eax"); +} + +/* Adds an arbitary amount to the cycle counter */ +static inline void add_to_cycles(int32_t val) +{ + val = -val; + asm("movd %0, %%mm2\n" + "paddd %%mm2, %%mm0\n" + : : "rm" (val)); +} Index: op_i386.h =================================================================== --- op_i386.h (nonexistent) +++ op_i386.h (revision 1765) @@ -0,0 +1,74 @@ +/* op_i386.h -- i386 specific support routines for micro operations + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "common_i386.h" + +#define OP_JUMP(x) asm("jmp *%0" : : "rm" (x)) + +#define FORCE_RET asm volatile ("") + +/* Handles the scheduler and PC updateing. Yes, useing MMX is a requirement. It + * just won't change. This must be as compact as possible */ +#define HANDLE_SCHED(func, jmp) asm("paddd %%mm1, %%mm0\n" \ + "\tmovd %%mm0, %%eax\n" \ + "\ttestl %%eax, %%eax\n" \ + "\tjg ." jmp "\n" \ + "\tcall "#func"\n" \ + "\t." jmp ":" : : ) + +static inline int32_t do_cycles(void) +{ + register uint32_t cycles; + + asm("paddd %%mm1, %%mm0\n" + "\tmovd %%mm0, %0\n" + : "=r" (cycles)); + return cycles; +} + +/* Joins runtime.sim.mem_cycles with the cycle counter */ +static inline void join_mem_cycles(void) +{ + runtime.sim.mem_cycles = -runtime.sim.mem_cycles; + asm volatile ("movd %0, %%mm2\n" + "\tpaddd %%mm2, %%mm0" + : : "m" (runtime.sim.mem_cycles)); + runtime.sim.mem_cycles = 0; +} + +static inline void or_longjmp(void *loc) __attribute__((noreturn)); +static inline void or_longjmp(void *loc) +{ + /* We push a trampoline address (dyn_ret_stack_prot) onto the stack to be able + * to detect if any ret instructions found their way into an operation. */ + asm("\tmovl %0, %%eax\n" + "\tmovl %1, %%esp\n" + "\tmovl $%2, %%ebp\n" + "\tpush $dyn_ret_stack_prot\n" + "\tpush $dyn_ret_stack_prot\n" + "\tpush $dyn_ret_stack_prot\n" + "\tjmp *%%eax\n" + : + : "m" (loc), + "m" (rec_stack_base), + "m" (cpu_state)); +} + + + Index: op_comp_op.h =================================================================== --- op_comp_op.h (nonexistent) +++ op_comp_op.h (revision 1765) @@ -0,0 +1,151 @@ +/* op_comp_op.h -- Micro operations template for comparison operations + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +__or_dynop void glue(glue(op_, COMP_NAME), _t0_t0)(void) +{ + if(COMP_CAST(t0) COMP COMP_CAST(t0)) + env->sprs[SPR_SR] |= SPR_SR_F; + else + env->sprs[SPR_SR] &= ~SPR_SR_F; +} + +__or_dynop void glue(glue(op_, COMP_NAME), _t0_t1)(void) +{ + if(COMP_CAST(t0) COMP COMP_CAST(t1)) + env->sprs[SPR_SR] |= SPR_SR_F; + else + env->sprs[SPR_SR] &= ~SPR_SR_F; + FORCE_RET; +} + +__or_dynop void glue(glue(op_, COMP_NAME), _t0_t2)(void) +{ + if(COMP_CAST(t0) COMP COMP_CAST(t2)) + env->sprs[SPR_SR] |= SPR_SR_F; + else + env->sprs[SPR_SR] &= ~SPR_SR_F; + FORCE_RET; +} + +__or_dynop void glue(glue(op_, COMP_NAME), _t1_t0)(void) +{ + if(COMP_CAST(t1) COMP COMP_CAST(t0)) + env->sprs[SPR_SR] |= SPR_SR_F; + else + env->sprs[SPR_SR] &= ~SPR_SR_F; + FORCE_RET; +} + +__or_dynop void glue(glue(op_, COMP_NAME), _t1_t1)(void) +{ + if(COMP_CAST(t1) COMP COMP_CAST(t1)) + env->sprs[SPR_SR] |= SPR_SR_F; + else + env->sprs[SPR_SR] &= ~SPR_SR_F; +} + +__or_dynop void glue(glue(op_, COMP_NAME), _t1_t2)(void) +{ + if(COMP_CAST(t1) COMP COMP_CAST(t2)) + env->sprs[SPR_SR] |= SPR_SR_F; + else + env->sprs[SPR_SR] &= ~SPR_SR_F; + FORCE_RET; +} + +__or_dynop void glue(glue(op_, COMP_NAME), _t2_t0)(void) +{ + if(COMP_CAST(t2) COMP COMP_CAST(t0)) + env->sprs[SPR_SR] |= SPR_SR_F; + else + env->sprs[SPR_SR] &= ~SPR_SR_F; + FORCE_RET; +} + +__or_dynop void glue(glue(op_, COMP_NAME), _t2_t1)(void) +{ + if(COMP_CAST(t2) COMP COMP_CAST(t1)) + env->sprs[SPR_SR] |= SPR_SR_F; + else + env->sprs[SPR_SR] &= ~SPR_SR_F; + FORCE_RET; +} + +__or_dynop void glue(glue(op_, COMP_NAME), _t2_t2)(void) +{ + if(COMP_CAST(t2) COMP COMP_CAST(t2)) + env->sprs[SPR_SR] |= SPR_SR_F; + else + env->sprs[SPR_SR] &= ~SPR_SR_F; +} + +__or_dynop void glue(glue(op_, COMP_NAME), _imm_t0)(void) +{ + if(COMP_CAST(t0) COMP COMP_CAST(OP_PARAM1)) + env->sprs[SPR_SR] |= SPR_SR_F; + else + env->sprs[SPR_SR] &= ~SPR_SR_F; + FORCE_RET; +} + +__or_dynop void glue(glue(op_, COMP_NAME), _imm_t1)(void) +{ + if(COMP_CAST(t1) COMP COMP_CAST(OP_PARAM1)) + env->sprs[SPR_SR] |= SPR_SR_F; + else + env->sprs[SPR_SR] &= ~SPR_SR_F; + FORCE_RET; +} + +__or_dynop void glue(glue(op_, COMP_NAME), _imm_t2)(void) +{ + if(COMP_CAST(t2) COMP COMP_CAST(OP_PARAM1)) + env->sprs[SPR_SR] |= SPR_SR_F; + else + env->sprs[SPR_SR] &= ~SPR_SR_F; + FORCE_RET; +} + +__or_dynop void glue(glue(op_, COMP_NAME), _null_t0)(void) +{ + if(COMP_CAST(t0) COMP 0) + env->sprs[SPR_SR] |= SPR_SR_F; + else + env->sprs[SPR_SR] &= ~SPR_SR_F; + FORCE_RET; +} + +__or_dynop void glue(glue(op_, COMP_NAME), _null_t1)(void) +{ + if(COMP_CAST(t1) COMP 0) + env->sprs[SPR_SR] |= SPR_SR_F; + else + env->sprs[SPR_SR] &= ~SPR_SR_F; + FORCE_RET; +} + +__or_dynop void glue(glue(op_, COMP_NAME), _null_t2)(void) +{ + if(COMP_CAST(t2) COMP 0) + env->sprs[SPR_SR] |= SPR_SR_F; + else + env->sprs[SPR_SR] &= ~SPR_SR_F; + FORCE_RET; +} Index: op_swhb_op.h =================================================================== --- op_swhb_op.h (nonexistent) +++ op_swhb_op.h (revision 1765) @@ -0,0 +1,150 @@ +/* op_swhb_op.h -- Micro operations template for store operations + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* FIXME: Do something with breakpoint */ + +__or_dynop void glue(glue(op_, S_OP_NAME), _t0_t0)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + S_FUNC(t0 + OP_PARAM1, t0, &breakpoint); +} + +__or_dynop void glue(glue(op_, S_OP_NAME), _t0_t1)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + S_FUNC(t0 + OP_PARAM1, t1, &breakpoint); +} + +__or_dynop void glue(glue(op_, S_OP_NAME), _t0_t2)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + S_FUNC(t0 + OP_PARAM1, t2, &breakpoint); +} + +__or_dynop void glue(glue(op_, S_OP_NAME), _t1_t1)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + S_FUNC(t1 + OP_PARAM1, t1, &breakpoint); +} + +__or_dynop void glue(glue(op_, S_OP_NAME), _t1_t0)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + S_FUNC(t1 + OP_PARAM1, t0, &breakpoint); +} + +__or_dynop void glue(glue(op_, S_OP_NAME), _t1_t2)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + S_FUNC(t1 + OP_PARAM1, t2, &breakpoint); +} + +__or_dynop void glue(glue(op_, S_OP_NAME), _t2_t0)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + S_FUNC(t2 + OP_PARAM1, t0, &breakpoint); +} + +__or_dynop void glue(glue(op_, S_OP_NAME), _t2_t1)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + S_FUNC(t2 + OP_PARAM1, t1, &breakpoint); +} + +__or_dynop void glue(glue(op_, S_OP_NAME), _t2_t2)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + S_FUNC(t2 + OP_PARAM1, t2, &breakpoint); +} + +__or_dynop void glue(glue(op_, S_OP_NAME), _imm_t0)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + S_FUNC(OP_PARAM1, t0, &breakpoint); +} + +__or_dynop void glue(glue(op_, S_OP_NAME), _imm_t1)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + S_FUNC(OP_PARAM1, t1, &breakpoint); +} + +__or_dynop void glue(glue(op_, S_OP_NAME), _imm_t2)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + S_FUNC(OP_PARAM1, t2, &breakpoint); +} + +__or_dynop void glue(glue(op_, S_OP_NAME), _clear_t0)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + S_FUNC(t0 + OP_PARAM1, 0, &breakpoint); +} + +__or_dynop void glue(glue(op_, S_OP_NAME), _clear_t1)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + S_FUNC(t1 + OP_PARAM1, 0, &breakpoint); +} + +__or_dynop void glue(glue(op_, S_OP_NAME), _clear_t2)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + S_FUNC(t2 + OP_PARAM1, 0, &breakpoint); +} + +__or_dynop void glue(glue(op_, S_OP_NAME), _clear_imm)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + S_FUNC(OP_PARAM1, 0, &breakpoint); +} + Index: sched_i386.h =================================================================== --- sched_i386.h (nonexistent) +++ sched_i386.h (revision 1765) @@ -0,0 +1,40 @@ +/* sched_i386.h -- i386 specific support routines for the scheduler + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* Sets the cycle counter to a specific value */ +static inline void set_sched_cycle(int32_t job_time) +{ + union { + uint64_t val64; + union { + uint32_t low32; + uint32_t high32; + } val3232; + } time_pc; + + asm("movq %%mm0, %0\n" + "\tmovl %2, %1\n" + "\tmovq %3, %%mm0\n" + : "=m" (time_pc.val64), + "=m" (time_pc.val3232.low32) + : "r" (job_time), + "m" (time_pc.val64)); +} + Index: op_arith_op.h =================================================================== --- op_arith_op.h (nonexistent) +++ op_arith_op.h (revision 1765) @@ -0,0 +1,201 @@ +/* op_arith_op.h -- Micro operations template for arithmetic operations + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +__or_dynop void glue(glue(op_, OP_NAME), _t0_t0_t0)(void) +{ + OP_CAST(t0) = OP_CAST(t0) OP OP_CAST(t0) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t0_t0_t1)(void) +{ + OP_CAST(t0) = OP_CAST(t0) OP OP_CAST(t1) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t0_t0_t2)(void) +{ + OP_CAST(t0) = OP_CAST(t0) OP OP_CAST(t2) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t0_t1_t0)(void) +{ + OP_CAST(t0) = OP_CAST(t1) OP OP_CAST(t0) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t0_t1_t1)(void) +{ + OP_CAST(t0) = OP_CAST(t1) OP OP_CAST(t1) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t0_t1_t2)(void) +{ + OP_CAST(t0) = OP_CAST(t1) OP OP_CAST(t2) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t0_t2_t0)(void) +{ + OP_CAST(t0) = OP_CAST(t2) OP OP_CAST(t0) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t0_t2_t1)(void) +{ + OP_CAST(t0) = OP_CAST(t2) OP OP_CAST(t1) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t0_t2_t2)(void) +{ + OP_CAST(t0) = OP_CAST(t2) OP OP_CAST(t2) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t1_t0_t0)(void) +{ + OP_CAST(t1) = OP_CAST(t0) OP OP_CAST(t0) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t1_t0_t1)(void) +{ + OP_CAST(t1) = OP_CAST(t0) OP OP_CAST(t1) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t1_t0_t2)(void) +{ + OP_CAST(t1) = OP_CAST(t0) OP OP_CAST(t2) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t1_t1_t0)(void) +{ + OP_CAST(t1) = OP_CAST(t1) OP OP_CAST(t0) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t1_t1_t1)(void) +{ + OP_CAST(t1) = OP_CAST(t1) OP OP_CAST(t1) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t1_t1_t2)(void) +{ + OP_CAST(t1) = OP_CAST(t1) OP OP_CAST(t2) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t1_t2_t0)(void) +{ + OP_CAST(t1) = OP_CAST(t2) OP OP_CAST(t0) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t1_t2_t1)(void) +{ + OP_CAST(t1) = OP_CAST(t2) OP OP_CAST(t1) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t1_t2_t2)(void) +{ + OP_CAST(t1) = OP_CAST(t2) OP OP_CAST(t2) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t2_t0_t0)(void) +{ + OP_CAST(t2) = OP_CAST(t0) OP OP_CAST(t0) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t2_t0_t1)(void) +{ + OP_CAST(t2) = OP_CAST(t0) OP OP_CAST(t1) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t2_t0_t2)(void) +{ + OP_CAST(t2) = OP_CAST(t0) OP OP_CAST(t2) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t2_t1_t0)(void) +{ + OP_CAST(t2) = OP_CAST(t1) OP OP_CAST(t0) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t2_t1_t1)(void) +{ + OP_CAST(t2) = OP_CAST(t1) OP OP_CAST(t1) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t2_t1_t2)(void) +{ + OP_CAST(t2) = OP_CAST(t1) OP OP_CAST(t2) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t2_t2_t0)(void) +{ + OP_CAST(t2) = OP_CAST(t2) OP OP_CAST(t0) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t2_t2_t1)(void) +{ + OP_CAST(t2) = OP_CAST(t2) OP OP_CAST(t1) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t2_t2_t2)(void) +{ + OP_CAST(t2) = OP_CAST(t2) OP OP_CAST(t2) OP_EXTRA; +} + +#ifdef OP_HAS_IMM +__or_dynop void glue(glue(op_, OP_NAME), _imm_t0_t0)(void) +{ + OP_CAST(t0) = OP_CAST(t0) OP OP_CAST(OP_PARAM1) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _imm_t0_t1)(void) +{ + OP_CAST(t0) = OP_CAST(t1) OP OP_CAST(OP_PARAM1) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _imm_t0_t2)(void) +{ + OP_CAST(t0) = OP_CAST(t2) OP OP_CAST(OP_PARAM1) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _imm_t1_t0)(void) +{ + OP_CAST(t1) = OP_CAST(t0) OP OP_CAST(OP_PARAM1) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _imm_t1_t1)(void) +{ + OP_CAST(t1) = OP_CAST(t1) OP OP_CAST(OP_PARAM1) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _imm_t1_t2)(void) +{ + OP_CAST(t1) = OP_CAST(t2) OP OP_CAST(OP_PARAM1) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _imm_t2_t0)(void) +{ + OP_CAST(t2) = OP_CAST(t0) OP OP_CAST(OP_PARAM1) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _imm_t2_t1)(void) +{ + OP_CAST(t2) = OP_CAST(t1) OP OP_CAST(OP_PARAM1) OP_EXTRA; +} + +__or_dynop void glue(glue(op_, OP_NAME), _imm_t2_t2)(void) +{ + OP_CAST(t2) = OP_CAST(t2) OP OP_CAST(OP_PARAM1) OP_EXTRA; +} +#endif /* OP_HAS_IMM */ Index: op_ff1_op.h =================================================================== --- op_ff1_op.h (nonexistent) +++ op_ff1_op.h (revision 1765) @@ -0,0 +1,35 @@ +/* op_ff1_op.h -- Micro operations template for the ff1 instruction + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +__or_dynop void glue(glue(glue(op_ff1_, DST_T), _), SRC_T)(void) +{ + int i; + + for(i = 0; i < 32; i++, SRC_T >>= 1) { + if(SRC_T & 1) { + DST_T = i; + break; + } + } + + FORCE_RET; +} + + Index: op_extend_op.h =================================================================== --- op_extend_op.h (nonexistent) +++ op_extend_op.h (revision 1765) @@ -0,0 +1,83 @@ +/* op_extend_op.h -- Micro operations template for sign extention operations + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +void glue(glue(op_, EXT_NAME), _t0_t0)(void) +{ + register EXT_TYPE x; + x = t0; + t0 = EXT_CAST x; +} + +void glue(glue(op_, EXT_NAME), _t0_t1)(void) +{ + register EXT_TYPE x; + x = t1; + t0 = EXT_CAST x; +} + +void glue(glue(op_, EXT_NAME), _t0_t2)(void) +{ + register EXT_TYPE x; + x = t2; + t0 = EXT_CAST x; +} + +void glue(glue(op_, EXT_NAME), _t1_t0)(void) +{ + register EXT_TYPE x; + x = t0; + t1 = EXT_CAST x; +} + +void glue(glue(op_, EXT_NAME), _t1_t1)(void) +{ + register EXT_TYPE x; + x = t1; + t1 = EXT_CAST x; +} + +void glue(glue(op_, EXT_NAME), _t1_t2)(void) +{ + register EXT_TYPE x; + x = t2; + t1 = EXT_CAST x; +} + +void glue(glue(op_, EXT_NAME), _t2_t0)(void) +{ + register EXT_TYPE x; + x = t0; + t2 = EXT_CAST x; +} + +void glue(glue(op_, EXT_NAME), _t2_t1)(void) +{ + register EXT_TYPE x; + x = t1; + t2 = EXT_CAST x; +} + +void glue(glue(op_, EXT_NAME), _t2_t2)(void) +{ + register EXT_TYPE x; + x = t2; + t2 = EXT_CAST x; +} + Index: dyngen_i386.c =================================================================== --- dyngen_i386.c (nonexistent) +++ dyngen_i386.c (revision 1765) @@ -0,0 +1,74 @@ +/* dyngen_i386.c -- i386 parts of dyngen + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include +#include +#include + +#include + +#include "dyngen.h" + +#define RET_OPCODE 0xc3 + +unsigned int i386_get_real_func_len(void *f_start, unsigned int f_len, char *name) +{ + if(((uint8_t *)f_start)[f_len - 1] != RET_OPCODE) { + fprintf(stderr, "`%s' does not have a ret at the end!\n", name); + exit(1); + } + + return f_len - 1; +} + +void i386_gen_reloc(FILE *f, struct reloc *reloc, unsigned int param) +{ + switch(reloc->type) { + case R_386_32: + fprintf(f, " *(uint32_t *)(host_page + %d) = *(ops_param + %u) + %d;\n", + reloc->func_offset, param - 1, reloc->addend); + break; + default: + fprintf(stderr, "Unknown i386 relocation: %i\n", reloc->type); + } +} + +void i386_gen_func_reloc(FILE *f, struct reloc *reloc) +{ + switch(reloc->type) { + case R_386_32: + /* This relocation is absolute. There is nothing to relocate (The linker + * handles this fine). */ + break; + case R_386_PC32: + fprintf(f, " *(uint32_t *)(host_page + %d) = (uint32_t)((%s + %d) - (unsigned int)(host_page + %d));\n", + reloc->func_offset, reloc->name, reloc->addend, reloc->func_offset); + break; + default: + fprintf(stderr, "Unknown i386 relocation: %i (symbol: %s)\n", reloc->type, + reloc->name); + } +} + +const struct archf archfs = { + i386_get_real_func_len, + i386_gen_reloc, + i386_gen_func_reloc +}; Index: op_mac_op.h =================================================================== --- op_mac_op.h (nonexistent) +++ op_mac_op.h (revision 1765) @@ -0,0 +1,80 @@ +/* op_mac_op.h -- Micro operations template for mac operations + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +__or_dynop void glue(glue(op_, OP_NAME), _t0_t0)(void) +{ + int64_t temp = env->sprs[SPR_MACLO] | ((int64_t)env->sprs[SPR_MACHI] << 32); + + temp OP (int64_t)t0 * (int64_t)t0; + + env->sprs[SPR_MACLO] = temp & 0xffffffff; + env->sprs[SPR_MACHI] = temp >> 32; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t0_t1)(void) +{ + int64_t temp = env->sprs[SPR_MACLO] | ((int64_t)env->sprs[SPR_MACHI] << 32); + + temp OP (int64_t)t0 * (int64_t)t1; + + env->sprs[SPR_MACLO] = temp & 0xffffffff; + env->sprs[SPR_MACHI] = temp >> 32; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t0_t2)(void) +{ + int64_t temp = env->sprs[SPR_MACLO] | ((int64_t)env->sprs[SPR_MACHI] << 32); + + temp OP (int64_t)t0 * (int64_t)t2; + + env->sprs[SPR_MACLO] = temp & 0xffffffff; + env->sprs[SPR_MACHI] = temp >> 32; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t1_t1)(void) +{ + int64_t temp = env->sprs[SPR_MACLO] | ((int64_t)env->sprs[SPR_MACHI] << 32); + + temp OP (int64_t)t1 * (int64_t)t1; + + env->sprs[SPR_MACLO] = temp & 0xffffffff; + env->sprs[SPR_MACHI] = temp >> 32; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t1_t2)(void) +{ + int64_t temp = env->sprs[SPR_MACLO] | ((int64_t)env->sprs[SPR_MACHI] << 32); + + temp OP (int64_t)t1 * (int64_t)t2; + + env->sprs[SPR_MACLO] = temp & 0xffffffff; + env->sprs[SPR_MACHI] = temp >> 32; +} + +__or_dynop void glue(glue(op_, OP_NAME), _t2_t2)(void) +{ + int64_t temp = env->sprs[SPR_MACLO] | ((int64_t)env->sprs[SPR_MACHI] << 32); + + temp OP (int64_t)t2 * (int64_t)t2; + + env->sprs[SPR_MACLO] = temp & 0xffffffff; + env->sprs[SPR_MACHI] = temp >> 32; +} + Index: common_i386.h =================================================================== --- common_i386.h (nonexistent) +++ common_i386.h (revision 1765) @@ -0,0 +1,63 @@ +/* common_i386.h -- Assembler routines used in rec_i386.h and op_i386.h + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* This is needed because we can't move an mmx register to a general purpose + * register. */ +static union { + struct { + uint32_t low32; + uint32_t high32; + } val3232; + uint64_t val64; +} useless_x86; + +/* Sets the PC with a specified value */ +static inline void set_pc(oraddr_t pc) +{ + /* I could just use pc as a memory argument, but if I do that then gcc may put + * the value of pc onto the stack, in which case gcc would also shift the + * stack twice, which would result in two add 4, %esp instructions and a + * mov %eax, *%esp, which would not only be slow but it would take up more + * space. */ + asm("movq %%mm0, %0\n" + "\tmovl %2, %1\n" + "\tmovq %3, %%mm0" + : "=m" (useless_x86.val64), + "=m" (useless_x86.val3232.high32) + : "r" (pc), + "m" (useless_x86.val64)); +} + +/* Returns the current value of the pc */ +static inline oraddr_t get_pc(void) +{ + asm("movq %%mm0, %0" : "=m" (useless_x86.val64)); + return useless_x86.val3232.high32; +} + +/* Updates the runtime.sim.cycles counter */ +static inline void upd_sim_cycles(void) +{ + asm volatile ("movq %%mm0, %0\n" : "=m" (useless_x86.val64)); + runtime.sim.cycles += scheduler.job_queue->time - useless_x86.val3232.low32; + scheduler.job_queue->time = useless_x86.val3232.low32; + cpu_state.pc = useless_x86.val3232.high32; +} + Index: dyngen_elf.c =================================================================== --- dyngen_elf.c (nonexistent) +++ dyngen_elf.c (revision 1765) @@ -0,0 +1,359 @@ +/* dyngen_elf.c -- Elf parser for dyngen + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include +#include +#include +#include + +#include + +#include "dyngen.h" + +struct elf_obj { + Elf32_Ehdr e_hdr; + Elf32_Shdr *e_shdrs; + void **e_sections; + Elf32_Sym *e_syms; /* The symbol table in the elf file */ + unsigned int e_sym_num; /* The number of symbols */ + unsigned int e_sym_str_tab; /* The string-table associated with symbols */ + Elf32_Rel *e_rels; + unsigned int e_rel_num; /* The number of relocations (in e_rel) */ + unsigned int e_rel_sym; + unsigned int e_rel_sec; /* The section to modify */ + Elf32_Rela *e_relas; + unsigned int e_rela_num; /* The number of relocations (in e_rela) */ + unsigned int e_rela_sym; + unsigned int e_rela_sec; /* The section to modify */ +}; + +void *elf_open_obj(const char *file) +{ + struct elf_obj *obj; + FILE *f; + int i; + + if(!(obj = malloc(sizeof(struct elf_obj)))) { + fprintf(stderr, "OOM\n"); + return NULL; + } + + if(!(f = fopen(file, "r"))) { + free(obj); + return NULL; + } + + fread(&obj->e_hdr, sizeof(Elf32_Ehdr), 1, f); + + /* Do some sanity checks */ + if((obj->e_hdr.e_ident[EI_MAG0] != ELFMAG0) || + (obj->e_hdr.e_ident[EI_MAG1] != ELFMAG1) || + (obj->e_hdr.e_ident[EI_MAG2] != ELFMAG2) || + (obj->e_hdr.e_ident[EI_MAG3] != ELFMAG3)) { + fprintf(stderr, "%s is not an elf file!\n", file); + goto error_load; + } + + if(obj->e_hdr.e_ident[EI_CLASS] == ELFCLASSNONE) { + fprintf(stderr, "Invalid class in ELF header\n"); + goto error_load; + } + + if(obj->e_hdr.e_ident[EI_DATA] == ELFDATANONE) { + fprintf(stderr, "Invalid data format in ELF header\n"); + goto error_load; + } + + /* FIXME: Swap data as necessary */ + + if((obj->e_hdr.e_ident[EI_VERSION] != 1) || + (obj->e_hdr.e_version != 1)) { + fprintf(stderr, "Unexpected elf version found: %i (%i)\n", + obj->e_hdr.e_ident[EI_VERSION], obj->e_hdr.e_version); + goto error_load; + } + + if(obj->e_hdr.e_type != ET_REL) { + fprintf(stderr, "Appears that we did not receive a object file\n"); + goto error_load; + } + + if(obj->e_hdr.e_phoff) { + fprintf(stderr, "What am I supposed to do with a program header??\n"); + goto error_load; + } + + if(obj->e_hdr.e_ehsize != sizeof(Elf32_Ehdr)) { + fprintf(stderr, "Unknown size of elf header\n"); + goto error_load; + } + + if(!obj->e_hdr.e_shoff || !obj->e_hdr.e_shnum) { + fprintf(stderr, "The elf file contains no sections!\n"); + goto error_load; + } + + if(obj->e_hdr.e_shentsize != sizeof(Elf32_Shdr)) { + fprintf(stderr, "Unknown section header size %i\n", obj->e_hdr.e_shentsize); + goto error_load; + } + + /* Load the section headers */ + if(!(obj->e_shdrs = malloc(obj->e_hdr.e_shentsize * obj->e_hdr.e_shnum))){ + fprintf(stderr, "OOM\n"); + goto error_load; + } + + fseek(f, obj->e_hdr.e_shoff, SEEK_SET); + fread(obj->e_shdrs, obj->e_hdr.e_shentsize, obj->e_hdr.e_shnum, f); + + /* FIXME: swap data */ + + /* Load the sections */ + if(!(obj->e_sections = calloc(obj->e_hdr.e_shnum, sizeof(void *)))) { + fprintf(stderr, "OOM\n"); + free(obj->e_shdrs); + goto error_load; + } + + for(i = 0; i < obj->e_hdr.e_shnum; i++) { + if(obj->e_shdrs[i].sh_type == SHT_NOBITS) + continue; + if(!(obj->e_sections[i] = malloc(obj->e_shdrs[i].sh_size))) { + fprintf(stderr, "OOM\n"); + goto post_sec_error_load; + } + fseek(f, obj->e_shdrs[i].sh_offset, SEEK_SET); + fread(obj->e_sections[i], obj->e_shdrs[i].sh_size, 1, f); + } + + obj->e_rels = NULL; + obj->e_syms = NULL; + obj->e_relas = NULL; + + /* Find the symbol table and relocation table(s) */ + for(i = 0; i < obj->e_hdr.e_shnum; i++) { + switch(obj->e_shdrs[i].sh_type) { + case SHT_SYMTAB: + if(obj->e_syms) { + fprintf(stderr, "ELF file has more than one symbol table\n"); + goto post_sec_error_load; + } + if(obj->e_shdrs[i].sh_entsize != sizeof(Elf32_Sym)) { + fprintf(stderr, "ELF symbol table entry size is unknown\n"); + goto post_sec_error_load; + } + if((obj->e_shdrs[i].sh_size % obj->e_shdrs[i].sh_entsize)) { + fprintf(stderr, "Symbol table's length is not a multiple of sizeof(Elf32_Sym\n"); + goto post_sec_error_load; + } + obj->e_syms = obj->e_sections[i]; + obj->e_sym_num = obj->e_shdrs[i].sh_size / obj->e_shdrs[i].sh_entsize; + obj->e_sym_str_tab = obj->e_shdrs[i].sh_link; + break; + case SHT_REL: + if(obj->e_rels) { + fprintf(stderr, "ELF file has more than one relocation table\n"); + goto post_sec_error_load; + } + if(obj->e_shdrs[i].sh_entsize != sizeof(Elf32_Rel)) { + fprintf(stderr, "ELF relocation table entry size is unknown\n"); + goto post_sec_error_load; + } + if((obj->e_shdrs[i].sh_size % obj->e_shdrs[i].sh_entsize)) { + fprintf(stderr, "Relocation table's length is not a multiple of sizeof(Elf32_Rel\n"); + goto post_sec_error_load; + } + obj->e_rels = obj->e_sections[i]; + obj->e_rel_sec = obj->e_shdrs[i].sh_info; + obj->e_rel_sym = obj->e_shdrs[i].sh_link; + obj->e_rel_num = obj->e_shdrs[i].sh_size / obj->e_shdrs[i].sh_entsize; + break; + case SHT_RELA: + if(obj->e_relas) { + fprintf(stderr, "ELF file has more than one a-relocation table\n"); + goto post_sec_error_load; + } + if(obj->e_shdrs[i].sh_entsize != sizeof(Elf32_Rela)) { + fprintf(stderr, "ELF a-relocation table entry size is unknown\n"); + goto post_sec_error_load; + } + if((obj->e_shdrs[i].sh_size % obj->e_shdrs[i].sh_entsize)) { + fprintf(stderr, "Relocation table's length is not a multiple of sizeof(Elf32_Rela)\n"); + goto post_sec_error_load; + } + obj->e_relas = obj->e_sections[i]; + obj->e_rela_sec = obj->e_shdrs[i].sh_info; + obj->e_rela_sym = obj->e_shdrs[i].sh_link; + obj->e_rela_num = obj->e_shdrs[i].sh_size / obj->e_shdrs[i].sh_entsize; + break; + } + } + + fclose(f); + return obj; + +post_sec_error_load: + for(i = 0; i < obj->e_hdr.e_shnum; i++) { + if(obj->e_sections[i]) + free(obj->e_sections[i]); + } + free(obj->e_sections); + free(obj->e_shdrs); +error_load: + free(obj); + fclose(f); + return NULL; +} + +void elf_close_obj(void *e_obj) +{ + struct elf_obj *obj = e_obj; + int i; + + for(i = 0; i < obj->e_hdr.e_shnum; i++) { + if(obj->e_sections[i]) + free(obj->e_sections[i]); + } + free(obj->e_sections); + free(obj->e_shdrs); + free(obj); +} + +static Elf32_Sym *elf_find_func(struct elf_obj *obj, unsigned int func) +{ + int i, j; + Elf32_Sym *cur; + + for(i = 0, j = 0, cur = obj->e_syms; i < obj->e_sym_num; i++, cur++) { + if(ELF32_ST_BIND(cur->st_info) != STB_GLOBAL) + continue; + if(ELF32_ST_TYPE(cur->st_info) != STT_FUNC) + continue; + if(j == func) + return cur; + j++; + } + return NULL; +} + +char *elf_get_func_name(void *e_obj, unsigned int func) +{ + struct elf_obj *obj = e_obj; + Elf32_Sym *func_sym = elf_find_func(obj, func); + + if(func_sym) + return obj->e_sections[obj->e_sym_str_tab] + func_sym->st_name; + + return NULL; +} + +unsigned int elf_get_func_len(void *e_obj, unsigned int func) +{ + struct elf_obj *obj = e_obj; + Elf32_Sym *func_sym = elf_find_func(obj, func); + + if(func_sym) + return func_sym->st_size; + return 0; +} + +void *elf_get_func_start(void *e_obj, unsigned int func) +{ + struct elf_obj *obj = e_obj; + Elf32_Sym *func_sym = elf_find_func(obj, func); + + if(!func_sym) + return NULL; + + if(func_sym->st_shndx == SHN_COMMON) { + fprintf(stderr, "Don't know how to handle SHN_COMMON section header\n"); + return NULL; + } + + return obj->e_sections[func_sym->st_shndx] + func_sym->st_value; +} + +static char *elf_get_sym_name(struct elf_obj *obj, unsigned int sym) +{ + char *name; + + name = obj->e_sections[obj->e_sym_str_tab]; + name += obj->e_syms[sym].st_name; + + return name; +} + +int elf_get_func_reloc(void *e_obj, unsigned int func, unsigned int relocn, + struct reloc *reloc) +{ + struct elf_obj *obj = e_obj; + Elf32_Sym *func_sym = elf_find_func(obj, func); + Elf32_Rel *cur; + Elf32_Rela *cura; + int i, j; + +/* + if(obj->e_rel_sec != func_sym->st_shndx) { + fprintf(stderr, "Don't know what to do: Function does not have a relocation table\n"); + return 0; + } +*/ + + for(i = 0, j = 0, cur = obj->e_rels; i < obj->e_rel_num; i++, cur++) { + if((cur->r_offset - func_sym->st_value) > func_sym->st_size) + continue; + if(relocn == j) { + reloc->name = elf_get_sym_name(obj, ELF32_R_SYM(cur->r_info)); + reloc->func_offset = cur->r_offset - func_sym->st_value; + reloc->type = ELF32_R_TYPE(cur->r_info); + /* FIXME: Byte-swap */ + reloc->addend = *(uint32_t *)(obj->e_sections[obj->e_rel_sec] + cur->r_offset); + return 1; + } + j++; + } + + if(!obj->e_relas) + return 0; + + for(i = 0, cura = obj->e_relas; i < obj->e_rela_num; i++, cura++) { + if((cura->r_offset - func_sym->st_value) > func_sym->st_size) + continue; + if(relocn == j) { + reloc->name = elf_get_sym_name(obj, ELF32_R_SYM(cur->r_info)); + reloc->func_offset = cura->r_offset - func_sym->st_value; + reloc->type = ELF32_R_TYPE(cur->r_info); + reloc->addend = cura->r_addend; + return 1; + } + j++; + } + + return 0; +} + +const struct bff bffs = { + elf_open_obj, + elf_close_obj, + elf_get_func_name, + elf_get_func_start, + elf_get_func_len, + elf_get_func_reloc }; Index: op_mftspr_op.h =================================================================== --- op_mftspr_op.h (nonexistent) +++ op_mftspr_op.h (revision 1765) @@ -0,0 +1,43 @@ +/* op_mftspr_op.h -- Micro operations template for the m{f,t}spr operations + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#ifndef ONLY_MTSPR +__or_dynop void glue(glue(glue(op_mfspr_, GPR_T_NAME), _), SPR_T_NAME)(void) +{ + /* FIXME: NPC/PPC Handling is br0ke */ + if(env->sprs[SPR_SR] & SPR_SR_SM) { + upd_sim_cycles(); + GPR_T = mfspr(SPR_T + OP_PARAM1); + } +} +#endif + +__or_dynop void glue(glue(glue(op_mtspr_, SPR_T_NAME), _), GPR_T_NAME)(void) +{ + /* FIXME: NPC handling DOES NOT WORK like this */ + if(env->sprs[SPR_SR] & SPR_SR_SM) { + upd_sim_cycles(); + /* Yes, an l.mtspr instruction can cause an exception if the immu is touched + * it might cause an ITLB miss of instruction page fault. */ + save_t_temporary(); + mtspr(SPR_T + OP_PARAM1, GPR_T); + } +} + Index: i386_regs.h =================================================================== --- i386_regs.h (nonexistent) +++ i386_regs.h (revision 1765) @@ -0,0 +1,26 @@ +/* i386_regs.h -- Register definitions for i386 + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#define CPU_STATE_REG "ebp" +#define T0_REG "ebx" +#define T1_REG "esi" +#define T2_REG "edi" + +#define NUM_T_REGS 3 Index: dyngen.h =================================================================== --- dyngen.h (nonexistent) +++ dyngen.h (revision 1765) @@ -0,0 +1,45 @@ +/* dyngen.h -- Definitions for dyngen.c + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +struct reloc { + unsigned int func_offset; + unsigned int addend; + int type; + const char *name; +}; + +struct bff { + void *(*open_obj)(const char *object); /* Open the object file */ + void (*close_obj)(void *); + char *(*get_func_name)(void *, unsigned int func); /* Gets the name of func */ + void *(*get_func_start)(void *, unsigned int func); + unsigned int (*get_func_len)(void *, unsigned int func); + int (*get_func_reloc)(void *, unsigned int func, unsigned int relocn, struct reloc *reloc); +}; + +extern const struct bff bffs; + +struct archf { + unsigned int (*get_real_func_len)(void *func, unsigned int len, char *name); + void (*gen_reloc)(FILE *f, struct reloc *reloc, unsigned int param); + void (*gen_func_reloc)(FILE *f, struct reloc *reloc); +}; + +extern const struct archf archfs; Index: op_lwhb_op.h =================================================================== --- op_lwhb_op.h (nonexistent) +++ op_lwhb_op.h (revision 1765) @@ -0,0 +1,118 @@ +/* op_lwhb_op.h -- Micro operations template for load operations + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* FIXME: Do something if a breakpoint is hit */ + +__or_dynop void glue(glue(op_, LS_OP_NAME), _t0_t0)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + t0 = LS_OP_CAST LS_OP_FUNC(t0 + OP_PARAM1, &breakpoint); +} + +__or_dynop void glue(glue(op_, LS_OP_NAME), _t0_t1)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + t0 = LS_OP_CAST LS_OP_FUNC(t1 + OP_PARAM1, &breakpoint); +} + +__or_dynop void glue(glue(op_, LS_OP_NAME), _t0_t2)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + t0 = LS_OP_CAST LS_OP_FUNC(t2 + OP_PARAM1, &breakpoint); +} + +__or_dynop void glue(glue(op_, LS_OP_NAME), _t1_t0)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + t1 = LS_OP_CAST LS_OP_FUNC(t0 + OP_PARAM1, &breakpoint); +} + +__or_dynop void glue(glue(op_, LS_OP_NAME), _t1_t1)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + t1 = LS_OP_CAST LS_OP_FUNC(t1 + OP_PARAM1, &breakpoint); +} + +__or_dynop void glue(glue(op_, LS_OP_NAME), _t1_t2)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + t1 = LS_OP_CAST LS_OP_FUNC(t2 + OP_PARAM1, &breakpoint); +} + +__or_dynop void glue(glue(op_, LS_OP_NAME), _t2_t0)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + t2 = LS_OP_CAST LS_OP_FUNC(t0 + OP_PARAM1, &breakpoint); +} + +__or_dynop void glue(glue(op_, LS_OP_NAME), _t2_t1)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + t2 = LS_OP_CAST LS_OP_FUNC(t1 + OP_PARAM1, &breakpoint); +} + +__or_dynop void glue(glue(op_, LS_OP_NAME), _t2_t2)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + t2 = LS_OP_CAST LS_OP_FUNC(t2 + OP_PARAM1, &breakpoint); +} + +__or_dynop void glue(glue(op_, LS_OP_NAME), _imm_t0)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + t0 = LS_OP_CAST LS_OP_FUNC(OP_PARAM1, &breakpoint); +} + +__or_dynop void glue(glue(op_, LS_OP_NAME), _imm_t1)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + t1 = LS_OP_CAST LS_OP_FUNC(OP_PARAM1, &breakpoint); +} + +__or_dynop void glue(glue(op_, LS_OP_NAME), _imm_t2)(void) +{ + int breakpoint; + upd_sim_cycles(); + save_t_temporary(); + t2 = LS_OP_CAST LS_OP_FUNC(OP_PARAM1, &breakpoint); +} + Index: simpl32_defs.h =================================================================== --- simpl32_defs.h (nonexistent) +++ simpl32_defs.h (revision 1765) @@ -0,0 +1,95 @@ +/* simpl32_defs.h -- Definitions for the simple execution model + Copyright (C) 1999 Damjan Lampret, lampret@opencores.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +extern void l_invalid PARAMS((struct iqueue_entry *)); +extern void l_sfne PARAMS((struct iqueue_entry *)); +extern void l_bf PARAMS((struct iqueue_entry *)); +extern void l_add PARAMS((struct iqueue_entry *)); +extern void l_addc PARAMS((struct iqueue_entry *)); +extern void l_sw PARAMS((struct iqueue_entry *)); +extern void l_sb PARAMS((struct iqueue_entry *)); +extern void l_sh PARAMS((struct iqueue_entry *)); +extern void l_lwz PARAMS((struct iqueue_entry *)); +extern void l_lbs PARAMS((struct iqueue_entry *)); +extern void l_lbz PARAMS((struct iqueue_entry *)); +extern void l_lhs PARAMS((struct iqueue_entry *)); +extern void l_lhz PARAMS((struct iqueue_entry *)); +extern void l_movhi PARAMS((struct iqueue_entry *)); +extern void l_and PARAMS((struct iqueue_entry *)); +extern void l_or PARAMS((struct iqueue_entry *)); +extern void l_xor PARAMS((struct iqueue_entry *)); +extern void l_sub PARAMS((struct iqueue_entry *)); +extern void l_mul PARAMS((struct iqueue_entry *)); +extern void l_div PARAMS((struct iqueue_entry *)); +extern void l_divu PARAMS((struct iqueue_entry *)); +extern void l_sll PARAMS((struct iqueue_entry *)); +extern void l_sra PARAMS((struct iqueue_entry *)); +extern void l_srl PARAMS((struct iqueue_entry *)); +extern void l_j PARAMS((struct iqueue_entry *)); +extern void l_jal PARAMS((struct iqueue_entry *)); +extern void l_jalr PARAMS((struct iqueue_entry *)); +extern void l_jr PARAMS((struct iqueue_entry *)); +extern void l_rfe PARAMS((struct iqueue_entry *)); +extern void l_nop PARAMS((struct iqueue_entry *)); +extern void l_bnf PARAMS((struct iqueue_entry *)); +extern void l_sfeq PARAMS((struct iqueue_entry *)); +extern void l_sfgts PARAMS((struct iqueue_entry *)); +extern void l_sfges PARAMS((struct iqueue_entry *)); +extern void l_sflts PARAMS((struct iqueue_entry *)); +extern void l_sfles PARAMS((struct iqueue_entry *)); +extern void l_sfgtu PARAMS((struct iqueue_entry *)); +extern void l_sfgeu PARAMS()(struct iqueue_entry *); +extern void l_sfltu PARAMS((struct iqueue_entry *)); +extern void l_sfleu PARAMS((struct iqueue_entry *)); +extern void l_extbs PARAMS((struct iqueue_entry *)); +extern void l_extbz PARAMS((struct iqueue_entry *)); +extern void l_exths PARAMS((struct iqueue_entry *)); +extern void l_exthz PARAMS((struct iqueue_entry *)); +extern void l_extws PARAMS((struct iqueue_entry *)); +extern void l_extwz PARAMS((struct iqueue_entry *)); +extern void l_mtspr PARAMS((struct iqueue_entry *)); +extern void l_mfspr PARAMS((struct iqueue_entry *)); +extern void l_sys PARAMS((struct iqueue_entry *)); +extern void l_trap PARAMS((struct iqueue_entry *)); /* CZ 21/06/01 */ +extern void l_macrc PARAMS((struct iqueue_entry *)); +extern void l_mac PARAMS((struct iqueue_entry *)); +extern void l_msb PARAMS((struct iqueue_entry *)); +extern void l_invalid PARAMS((struct iqueue_entry *)); +extern void l_cmov PARAMS ((struct iqueue_entry *)); +extern void l_ff1 PARAMS ((struct iqueue_entry *)); +extern void l_cust1 PARAMS ((struct iqueue_entry *)); +extern void l_cust2 PARAMS ((struct iqueue_entry *)); +extern void l_cust3 PARAMS ((struct iqueue_entry *)); +extern void l_cust4 PARAMS ((struct iqueue_entry *)); +extern void lf_add_s PARAMS ((struct iqueue_entry *)); +extern void lf_div_s PARAMS ((struct iqueue_entry *)); +extern void lf_ftoi_s PARAMS ((struct iqueue_entry *)); +extern void lf_itof_s PARAMS ((struct iqueue_entry *)); +extern void lf_madd_s PARAMS ((struct iqueue_entry *)); +extern void lf_mul_s PARAMS ((struct iqueue_entry *)); +extern void lf_rem_s PARAMS ((struct iqueue_entry *)); +extern void lf_sfeq_s PARAMS ((struct iqueue_entry *)); +extern void lf_sfge_s PARAMS ((struct iqueue_entry *)); +extern void lf_sfgt_s PARAMS ((struct iqueue_entry *)); +extern void lf_sfle_s PARAMS ((struct iqueue_entry *)); +extern void lf_sflt_s PARAMS ((struct iqueue_entry *)); +extern void lf_sfne_s PARAMS ((struct iqueue_entry *)); +extern void lf_sub_s PARAMS((struct iqueue_entry *)); +extern void l_none PARAMS((struct iqueue_entry *)); + Index: generate.c =================================================================== --- generate.c (nonexistent) +++ generate.c (revision 1765) @@ -0,0 +1,392 @@ +/* generate.c -- generates file execgen.c from instruction set + Copyright (C) 1999 Damjan Lampret, lampret@opencores.org + Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include + +#include "config.h" +#include "opcode/or32.h" + +static char *in_file; +static char *out_file; + +/* Whether this instruction stores something in register */ +static int write_to_reg; + +static int out_lines = 0; + +void debug(int level, const char *format, ...) +{ +#if DEBUG + char *p; + va_list ap; + + if ((p = malloc(1000)) == NULL) + return; + va_start(ap, format); + (void) vsnprintf(p, 1000, format, ap); + va_end(ap); + printf("%s\n", p); + fflush(stdout); + free(p); +#endif +} + +static int shift_fprintf(int level, FILE *f, const char *fmt, ...) +{ + va_list ap; + int i; + + va_start(ap, fmt); + for(i = 0; i < level; i++) + fprintf(f, " "); + + i = vfprintf(f, fmt, ap); + va_end(ap); + + out_lines++; + return i + (level * 2); +} + +/* Generates a execute sequence for one instruction */ +int output_function (FILE *fo, const char *func_name, int level) +{ + FILE *fi; + int olevel; + int line_num = 0; + + if ((fi = fopen (in_file, "rt")) == NULL) { + printf("could not open file\n"); + return 1; + } + + while (!feof (fi)) { + char line[10000], *str = line; + fgets (str, sizeof (line), fi); + line[sizeof (line) - 1] = 0; + line_num++; + if (strncmp (str, "INSTRUCTION (", 13) == 0) { + char *s; + str += 13; + while (isspace (*str)) str++; + s = str; + while (*s && *s != ')') s++; + *s = 0; + while (isspace(*(s - 1))) s--; + *s = 0; + if (strcmp (str, func_name) == 0) { + olevel = 1; + str += strlen (str) + 1; + while (isspace (*str)) str++; + s = str; + while (*s && *s != '\n' && *s != '\r') s++; + *s = 0; + while (isspace(*(s - 1))) s--; + *s = 0; + /*shift_fprintf (level, fo, "#line %i \"%s\"\n", line_num, in_file);*/ + shift_fprintf (level, fo, "%s", str); + shift_fprintf (level, fo, " /* \"%s\" */\n", func_name); + do { + fgets (line, sizeof (line), fi); + line[sizeof(line) - 1] = 0; + for (str = line; *str; str++) { + if (*str == '{') olevel++; + else if (*str == '}') olevel--; + } + shift_fprintf (level, fo, "%s", line); + } while (olevel); + fclose(fi); + /*shift_fprintf (level, fo, "#line %i \"%s\"\n", out_lines, out_file);*/ + return 0; + } + } + } + shift_fprintf (level, fo, "%s ();\n", func_name); + + fclose(fi); + return 0; +} + +/* Parses operands. */ + +static int +gen_eval_operands (FILE *fo, int insn_index, int level) +{ + struct insn_op_struct *opd = op_start[insn_index]; + int i; + int num_ops; + int nbits = 0; + int set_param = 0; + int dis = 0; + int sbit; + int dis_op = -1; + + write_to_reg = 0; + + shift_fprintf (level, fo, "uorreg_t "); + + /* Count number of operands */ + for (i = 0, num_ops = 0;; i++) { + if (!(opd[i].type & OPTYPE_OP)) + continue; + if (opd[i].type & OPTYPE_DIS) + continue; + if (num_ops) + fprintf(fo, ", "); + fprintf(fo, "%c", 'a' + num_ops); + num_ops++; + if (opd[i].type & OPTYPE_LAST) + break; + } + + fprintf (fo, ";\n"); + + shift_fprintf (level, fo, "/* Number of operands: %i */\n", num_ops); + + i = 0; + num_ops = 0; + do { +/* + printf("opd[%i].type = %c\n", i, opd->type & OPTYPE_LAST ? '1' : '0'); printf("opd[%i].type = %c\n", i, opd->type & OPTYPE_OP ? '1' : '0'); + printf("opd[%i].type = %c\n", i, opd->type & OPTYPE_REG ? '1' : '0'); + printf("opd[%i].type = %c\n", i, opd->type & OPTYPE_SIG ? '1' : '0'); + printf("opd[%i].type = %c\n", i, opd->type & OPTYPE_DIS ? '1' : '0'); + printf("opd[%i].type = %i\n", i, opd->type & OPTYPE_SHR); + printf("opd[%i].type = %i\n", i, (opd->type & OPTYPE_SBIT) >> OPTYPE_SBIT_SHR); + printf("opd[%i].data = %i\n", i, opd->data); +*/ + + if (!nbits) + shift_fprintf (level, fo, "%c = (insn >> %i) & 0x%x;\n", 'a' + num_ops, + opd->type & OPTYPE_SHR, (1 << opd->data) - 1); + else + shift_fprintf (level, fo, "%c |= ((insn >> %i) & 0x%x) << %i;\n", + 'a' + num_ops, opd->type & OPTYPE_SHR, + (1 << opd->data) - 1, nbits); + + nbits += opd->data; + + if ((opd->type & OPTYPE_DIS) && (opd->type & OPTYPE_OP)) { + sbit = (opd->type & OPTYPE_SBIT) >> OPTYPE_SBIT_SHR; + if (opd->type & OPTYPE_SIG) + shift_fprintf (level, fo, "if(%c & 0x%08x) %c |= 0x%x;\n", + 'a' + num_ops, 1 << sbit, 'a' + num_ops, + 0xffffffff << sbit); + opd++; + shift_fprintf (level, fo, "(signed)%c += (signed)cpu_state.reg[(insn >> %i) & 0x%x];\n", + 'a' + num_ops, opd->type & OPTYPE_SHR, + (1 << opd->data) - 1); + dis = 1; + dis_op = num_ops; + } + + if (opd->type & OPTYPE_OP) { + sbit = (opd->type & OPTYPE_SBIT) >> OPTYPE_SBIT_SHR; + if (opd->type & OPTYPE_SIG) + shift_fprintf (level, fo, "if(%c & 0x%08x) %c |= 0x%x;\n", + 'a' + num_ops, 1 << sbit, 'a' + num_ops, + 0xffffffff << sbit); + if ((opd->type & OPTYPE_REG) && !dis) { + if(!i) { + shift_fprintf (level, fo, "#define SET_PARAM0(val) cpu_state.reg[a] = val\n"); + set_param = 1; + } + shift_fprintf (level, fo, "#define PARAM%i cpu_state.reg[%c]\n", num_ops, + 'a' + num_ops); + if(opd->type & OPTYPE_DST) + write_to_reg = 1; + } else { + shift_fprintf (level, fo, "#define PARAM%i %c\n", num_ops, + 'a' + num_ops); + } + num_ops++; + nbits = 0; + dis = 0; + } + + if ((opd->type & OPTYPE_LAST)) + break; + opd++; + i++; + } while (1); + + output_function (fo, or32_opcodes[insn_index].function_name, level); + + if (set_param) + shift_fprintf (level, fo, "#undef SET_PARAM\n"); + + for (i = 0; i < num_ops; i++) + shift_fprintf (level, fo, "#undef PARAM%i\n", i); + + return dis_op; +} + +/* Generates decode and execute for one instruction instance */ +static int output_call (FILE *fo, int index, int level) +{ + int dis_op = -1; + + /*printf ("%i:%s\n", index, insn_name (index));*/ + + shift_fprintf (level++, fo, "{\n"); + + if (index >= 0) + dis_op = gen_eval_operands (fo, index, level); + + if (index < 0) output_function (fo, "l_invalid", level); + + fprintf (fo, "\n"); + + shift_fprintf (level++, fo, "if (do_stats) {\n"); + + if (dis_op >= 0) + shift_fprintf (level, fo, "cpu_state.insn_ea = %c;\n", 'a' + dis_op); + + shift_fprintf (level, fo, "current->insn_index = %i; /* \"%s\" */\n", index, + insn_name (index)); + + shift_fprintf (level, fo, "analysis(current);\n"); + shift_fprintf (--level, fo, "}\n"); + + if (write_to_reg) + shift_fprintf (level, fo, "cpu_state.reg[0] = 0; /* Repair in case we changed it */\n"); + shift_fprintf (--level, fo, "}\n"); + return 0; +} + +/* Generates .c file header */ +static int generate_header (FILE *fo) +{ + fprintf (fo, "/* This file was automatically generated by generate (see cpu/or32/generate.c) */\n\n"); + fprintf (fo, "static inline void decode_execute (struct iqueue_entry *current)\n{\n"); + fprintf (fo, " uint32_t insn = current->insn;\n"); + out_lines = 5; + return 0; +} + +/* Generates .c file footer */ +static int generate_footer (FILE *fo) +{ + fprintf (fo, "}\n"); + return 0; +} + +/* Decodes all instructions and generates code for that. This function + is similar to insn_decode, except it decodes all instructions. */ +static int generate_body (FILE *fo, unsigned long *a, unsigned long cur_mask, int level) +{ + unsigned long shift = *a; + unsigned long mask; + int i; + int prev_inv = 0; + + if (!(*a & LEAF_FLAG)) { + shift = *a++; + mask = *a++; + shift_fprintf (level, fo, "switch((insn >> %i) & 0x%x) {\n", shift, + mask); + for (i = 0; i <= mask; i++, a++) { + if (!*a) { + shift_fprintf (level, fo, "case 0x%x:\n", i); + prev_inv = 1; + } else { + if(prev_inv) { + shift_fprintf (++level, fo, "/* Invalid instruction(s) */\n"); + shift_fprintf (level--, fo, "break;\n"); + } + shift_fprintf (level, fo, "case 0x%x:\n", i); + generate_body (fo, automata + *a, cur_mask | (mask << shift), ++level); + shift_fprintf (level--, fo, "break;\n"); + prev_inv = 0; + } + } + if (prev_inv) { + shift_fprintf (++level, fo, "/* Invalid instruction(s) */\n"); + shift_fprintf (level--, fo, "break;\n"); + } + shift_fprintf (level, fo, "}\n"); + } else { + i = *a & ~LEAF_FLAG; + + /* Final check - do we have direct match? + (based on or32_opcodes this should be the only possibility, + but in case of invalid/missing instruction we must perform a check) */ + + if (ti[i].insn_mask != cur_mask) { + shift_fprintf (level, fo, "/* Not unique: real mask %08lx and current mask %08lx differ - do final check */\n", ti[i].insn_mask, cur_mask); + shift_fprintf (level++, fo, "if((insn & 0x%x) == 0x%x) {\n", + ti[i].insn_mask, ti[i].insn); + } + shift_fprintf (level, fo, "/* Instruction: %s */\n", or32_opcodes[i].name); + + output_call (fo, i, level); + + if (ti[i].insn_mask != cur_mask) { + shift_fprintf (--level, fo, "} else {\n"); + shift_fprintf (++level, fo, "/* Invalid insn */\n"); + output_call (fo, -1, level); + shift_fprintf (--level, fo, "}\n"); + } + } + return 0; +} + +/* Main function; it takes two parameters: + input_file(possibly insnset.c) output_file(possibly execgen.c)*/ +int main (int argc, char *argv[]) +{ + FILE *fo; + + if (argc != 3) { + fprintf (stderr, "USAGE: generate input_file(possibly insnset.c) output_file(possibly execgen.c)\n"); + exit (-1); + } + + in_file = argv[1]; + out_file = argv[2]; + if (!(fo = fopen (argv[2], "wt+"))) { + fprintf (stderr, "Cannot create '%s'.\n", argv[2]); + exit (1); + } + + build_automata (); + if (generate_header (fo)) { + fprintf (stderr, "generate_header\n"); + return 1; + } + + if (generate_body (fo, automata, 0, 1)) { + fprintf (stderr, "generate_body\n"); + return 1; + } + + if (generate_footer (fo)) { + fprintf (stderr, "generate_footer\n"); + return 1; + } + + fclose (fo); + destruct_automata (); + return 0; +} +
generate.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: Makefile.in =================================================================== --- Makefile.in (nonexistent) +++ Makefile.in (revision 1765) @@ -0,0 +1,368 @@ +# Makefile.in generated by automake 1.6.3 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile -- Makefile for OR32 dependent simulation +# Copyright (C) 1999 Damjan Lampret, lampret@opencores.org +# +# This file is part of OpenRISC 1000 Architectural Simulator. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_HEADER = $(INSTALL_DATA) +transform = @program_transform_name@ +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ + +EXEEXT = @EXEEXT@ +OBJEXT = @OBJEXT@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +AMTAR = @AMTAR@ +AR = @AR@ +ARFLAGS = @ARFLAGS@ +AWK = @AWK@ +BUILD_DIR = @BUILD_DIR@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPU_ARCH = @CPU_ARCH@ +DEPDIR = @DEPDIR@ +INCLUDES = @INCLUDES@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LOCAL_CFLAGS = @LOCAL_CFLAGS@ +LOCAL_DEFS = @LOCAL_DEFS@ +MAKE_SHELL = @MAKE_SHELL@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +STRIP = @STRIP@ +SUMVERSION = @SUMVERSION@ +TERMCAP_LIB = @TERMCAP_LIB@ +VERSION = @VERSION@ +am__include = @am__include@ +am__quote = @am__quote@ +host = @host@ +host_cpu = @host_cpu@ +host_os = @host_os@ +install_sh = @install_sh@ + +noinst_LIBRARIES = libarch.a +libarch_a_SOURCES = execute.c or32.c + +@SIMPLE_EXECUTION_TRUE@noinst_PROGRAMS = +@SIMPLE_EXECUTION_FALSE@noinst_PROGRAMS = generate +@SIMPLE_EXECUTION_TRUE@generate_SOURCES = +@SIMPLE_EXECUTION_FALSE@generate_SOURCES = or32.c generate.c +@SIMPLE_EXECUTION_FALSE@BUILT_SOURCES = execgen.c + +# If the simulator was first built without --enable-simple and then with it, +# then also remove these two files +CLEANFILES = execgen.c generate +subdir = cpu/or32 +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + +libarch_a_AR = $(AR) cru +libarch_a_LIBADD = +am_libarch_a_OBJECTS = execute.$(OBJEXT) or32.$(OBJEXT) +libarch_a_OBJECTS = $(am_libarch_a_OBJECTS) +@SIMPLE_EXECUTION_TRUE@noinst_PROGRAMS = +@SIMPLE_EXECUTION_FALSE@noinst_PROGRAMS = generate$(EXEEXT) +PROGRAMS = $(noinst_PROGRAMS) + +@SIMPLE_EXECUTION_TRUE@am_generate_OBJECTS = +@SIMPLE_EXECUTION_FALSE@am_generate_OBJECTS = or32.$(OBJEXT) \ +@SIMPLE_EXECUTION_FALSE@ generate.$(OBJEXT) +generate_OBJECTS = $(am_generate_OBJECTS) +generate_LDADD = $(LDADD) +generate_DEPENDENCIES = +generate_LDFLAGS = + +DEFS = @DEFS@ +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/execute.Po ./$(DEPDIR)/generate.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/or32.Po +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libarch_a_SOURCES) $(generate_SOURCES) +DIST_COMMON = Makefile.am Makefile.in +SOURCES = $(libarch_a_SOURCES) $(generate_SOURCES) + +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu cpu/or32/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libarch.a: $(libarch_a_OBJECTS) $(libarch_a_DEPENDENCIES) + -rm -f libarch.a + $(libarch_a_AR) libarch.a $(libarch_a_OBJECTS) $(libarch_a_LIBADD) + $(RANLIB) libarch.a + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) +generate$(EXEEXT): $(generate_OBJECTS) $(generate_DEPENDENCIES) + @rm -f generate$(EXEEXT) + $(LINK) $(generate_LDFLAGS) $(generate_OBJECTS) $(generate_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/execute.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/generate.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/or32.Po@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.c.o: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< + +.c.obj: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c `cygpath -w $<` +CCDEPMODE = @CCDEPMODE@ +uninstall-info-am: + +ETAGS = etags +ETAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = ../.. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @list='$(DISTFILES)'; for file in $$list; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(PROGRAMS) + +installdirs: + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +uninstall-am: uninstall-info-am + +.PHONY: GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES clean-noinstPROGRAMS distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-tags distdir dvi dvi-am info info-am install \ + install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic tags uninstall \ + uninstall-am uninstall-info-am + + +@SIMPLE_EXECUTION_FALSE@execgen.c: generate $(srcdir)/insnset.c +@SIMPLE_EXECUTION_FALSE@ ./generate $(srcdir)/insnset.c execgen.c +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: Index: . =================================================================== --- . (nonexistent) +++ . (revision 1765)
. Property changes : Added: svn:ignore ## -0,0 +1,3 ## +Makefile +.deps +generate

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.