tx79Lib.c
上传用户:smqsbj
上传日期:2019-04-24
资源大小:9972k
文件大小:14k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* tx79Lib.c - Toshiba Tx79 support library */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5.  * This file has been developed or significantly modified by the
  6.  * MIPS Center of Excellence Dedicated Engineering Staff.
  7.  * This notice is as per the MIPS Center of Excellence Master Partner
  8.  * Agreement, do not remove this notice without checking first with
  9.  * WR/Platforms MIPS Center of Excellence engineering management.
  10.  */
  11. /*
  12. modification history
  13. --------------------
  14. 01c,15nov02,jmt  Add Interrupt Exception Handler
  15. 01b,03oct02,jmt  Modify to resolve code review issues
  16. 01a,04sep02,jmt  written.
  17. */
  18. /*
  19. DESCRIPTION
  20. This library provides a low-level support for the Toshiba Tx79 processor.
  21. INITIALIZATION
  22. SEE ALSO:
  23. */
  24. #include "vxWorks.h"
  25. #include "iv.h"
  26. #include "intLib.h"
  27. #include "esf.h"
  28. #include "arch/mips/dsmMipsLib.h"
  29. /* imports */
  30. extern void excNormVecInit(void *vecAdrs);
  31. #if (CPU == MIPS64)
  32. extern void excExcHandle(int vecNum, ESFMIPS * pEsf, REG_SET * pRegs);
  33. extern STATUS fppEmulateBranch (ESFMIPS *pEsf, uint32_t brInstr,
  34. uint32_t fpcsr);
  35. extern void tx79AMult64(uint64_t j, uint64_t k, uint64_t* pResLow,
  36. uint64_t* pResHigh);
  37. #endif /* (CPU == MIPS64) */
  38. /* globals */
  39. /* The define below this comment will enable the use of the C language
  40.  * version of the 64 bit mult (tx79Mult64) instead of the Asm version.
  41.  * They both do the same job, the assembly is faster.
  42.  */
  43. /* #define USE_C_MULT64_ROUTINE */
  44. /* Instruction Encodings for Unsupported Instructions
  45.  *
  46.  * Note: Mask only allows for two operand instructions (per MIPS spec)
  47.  */
  48. #define INSTR_MASK         (0xFC00FFFF)
  49. #define DDIV_INSTR         (0x0000001E)
  50. #define DDIVU_INSTR        (0x0000001F)
  51. #define DMULT_INSTR        (0x0000001C)
  52. #define DMULTU_INSTR       (0x0000001D)
  53. #if 0
  54. /* for testing on tx49 */
  55. #define DDIV_INSTR         (0x00000001)
  56. #define DDIVU_INSTR        (0x00000005)
  57. #define DMULT_INSTR        (0x0000000a)
  58. #define DMULTU_INSTR       (0x0000000b)
  59. #endif
  60. /* Interrupt Exception Definition */
  61. #define TX79_INT_VEC       (K0BASE+0x200)          /* interrupt vector */
  62. #if (CPU == MIPS64)
  63. /* Protect from initializing more than once */
  64. uint8_t tx79LibInitialized = FALSE;
  65. /* storage for old Reserved Inst Handler */
  66. typedef void (*resIntHandlerType)(int vecNum, ESFMIPS * pEsf, REG_SET * pRegs);
  67. resIntHandlerType oldResInstHandler;
  68. #endif  /* (CPU == MIPS64) */
  69. /* forward declarations */
  70. #if (CPU == MIPS64)
  71. void tx79ResvdInstHandler (int vectorNum, ESFMIPS *pEsf, REG_SET *pRegs);
  72. void tx79ddiv(uint64_t j, uint64_t k, uint64_t* pRes, uint64_t* pRem);
  73. void tx79ddivu(uint64_t j, uint64_t k, uint64_t* pRes, uint64_t* pRem);
  74. void tx79dmult(uint64_t j, uint64_t k, uint64_t* pResLow, uint64_t* pResHigh);
  75. void tx79dmultu(uint64_t j, uint64_t k, uint64_t* pResLow, uint64_t* pResHigh);
  76. #endif /* (CPU == MIPS64) */
  77. /******************************************************************************
  78. *
  79. * tx79ArchInit - initialize tx79 support.
  80. *
  81. * This routine must be called before using unsupported 64 bit mult/div
  82. * instructions.
  83. *
  84. * NOMANUAL
  85. */
  86. void tx79ArchInit (void)
  87.     {
  88.     /* initialize Interrupt Exception Handler */
  89.     excNormVecInit((void *) TX79_INT_VEC);
  90. #if (CPU == MIPS64)
  91.     /* only initialize once */
  92.     
  93.     if (tx79LibInitialized == FALSE)
  94. {
  95. tx79LibInitialized = TRUE;
  96. /* save old reserved instruction handler */
  97.     
  98. oldResInstHandler = (resIntHandlerType)
  99.   intVecGet((FUNCPTR *) INUM_TO_IVEC(IV_RESVDINST_VEC));
  100.     
  101. /* Register Reserved Instruction Handler */
  102.     
  103. intVecSet((FUNCPTR *) INUM_TO_IVEC(IV_RESVDINST_VEC),
  104.   (FUNCPTR) tx79ResvdInstHandler);
  105. }
  106. #endif /* (CPU == MIPS64) */
  107.     }
  108. #if (CPU == MIPS64)
  109. /* Tx79 does not support 64-bit mult/div insns */
  110. /******************************************************************************
  111. *
  112. * tx79ResvdInstHandler - Reserved Instruction Handler for the TX79
  113. *
  114. * This routine is called when a Reserved Instruction exception is raised
  115. * in the TX79.  If the instruction is an unsupported 64 bit mult/div
  116. * instruction, we will simulate the instruction and return.  Otherwise,
  117. * we will raise an exception by calling excExcHandle.
  118. *
  119. * NOMANUAL
  120. */
  121. void tx79ResvdInstHandler
  122.     (
  123.     int vectorNum,
  124.     ESFMIPS *pEsf,
  125.     REG_SET *pRegs
  126.     )
  127.     {
  128.     INSTR instruction;
  129.     INSTR *pNextInstr;
  130.     STATUS status;
  131.     REGISTERTYPE *pInstrDecode;
  132.     uint64_t rs;
  133.     uint64_t rt;
  134.     uint64_t resultHigh;
  135.     uint64_t resultLow;
  136.     
  137.     /* Determine the PC for the instruction that caused the exception */
  138.     instruction = *pRegs->pc;
  139.     /* calculate return address */
  140.     /* Check to see if the instruction was in a Branch Delay slot */
  141.     if ((pEsf->cause & CAUSE_BD) != 0)
  142. {
  143. /* Instruction is in the branch delay slot, simulate the branch */
  144. pNextInstr =
  145.   (INSTR *) fppEmulateBranch(pEsf, instruction, pEsf->fpcsr);
  146. if ((int) pNextInstr == 1)
  147.     {
  148.     /* branch emulation failed, raise exception */
  149.     if (oldResInstHandler != NULL)
  150. {
  151. oldResInstHandler(vectorNum, pEsf, pRegs);
  152. }
  153.     else
  154. {
  155. excExcHandle(vectorNum, pEsf, pRegs);
  156. }
  157.     }
  158. }
  159.     else
  160. {
  161. pNextInstr = pRegs->pc + 1;
  162. }
  163.     /* decode instruction */
  164.     status = OK;
  165.     switch (instruction & INSTR_MASK)
  166. {
  167. case DMULT_INSTR:
  168. case DMULTU_INSTR:
  169. case DDIV_INSTR:
  170. case DDIVU_INSTR:
  171.     /* decode the instruction */
  172.     pInstrDecode = (REGISTERTYPE *) &instruction;
  173.     rs = pRegs->gpreg[pInstrDecode->rs];
  174.     rt = pRegs->gpreg[pInstrDecode->rt];
  175.     /* emulate instruction */
  176.     
  177.     switch (instruction & INSTR_MASK)
  178. {
  179. case DMULT_INSTR:
  180.     tx79dmult(rs, rt, &resultLow, &resultHigh);
  181.     break;
  182. case DMULTU_INSTR:
  183.     tx79dmultu(rs, rt, &resultLow, &resultHigh);
  184.     break;
  185. case DDIV_INSTR:
  186.     tx79ddiv(rs, rt, &resultLow, &resultHigh);
  187.     break;
  188. case DDIVU_INSTR:
  189.     tx79ddivu(rs, rt, &resultLow, &resultHigh);
  190.     break;
  191. }
  192.     /* save results in hi and lo */
  193.     pRegs->hi = resultHigh;
  194.     pRegs->lo = resultLow;
  195.     
  196.     break;
  197.     
  198. default:
  199.     status = ERROR;
  200.     break;
  201. }
  202.     /* if the instruction was successfully emulated, return to the
  203.      * instruction after the emulated instruction
  204.      */
  205.     if (status == OK)
  206. {
  207. /* update the epc to point to the next instruction */
  208. pRegs->pc = pNextInstr;
  209. }
  210.     else
  211. {
  212. /* raise exception */
  213. excExcHandle(vectorNum, pEsf, pRegs);
  214. }
  215.     }
  216. /******************************************************************************
  217. *
  218. * tx79Div64 - perform a 64 bit unsigned divide
  219. *
  220. * This routine does a 64 bit unsigned divide and returns the result and
  221. * remainder.  Do not call this routine directly, call either tx79ddiv or
  222. * tx79ddivu.
  223. *
  224. * NOMANUAL
  225. */
  226. static void tx79Div64(uint64_t j,
  227.       uint64_t k,
  228.       uint64_t *pRes,
  229.       uint64_t *pRem)
  230.     {
  231.     int64_t i, m;
  232.     uint64_t n;
  233.     uint32_t c;
  234.     if (((k-1) & k) == 0)
  235. {
  236. /* Divide by power of 2. */
  237. *pRem = j & (k-1);
  238. /* shift value until k = 1 */
  239. n = j;
  240. if((k & 0x00000000ffffffffll) == 0)
  241.     {
  242.     k >>= 32;
  243.     n >>= 32;
  244.     }
  245. c = k;
  246. if((c & 0xffff) == 0)
  247.     {
  248.     c >>= 16;
  249.     n >>= 16;
  250.     }
  251. if((c & 0xff) == 0)
  252.     {
  253.     c >>= 8;
  254.     n >>= 8;
  255.     }
  256. while (c >>= 1)
  257.     {
  258.     n >>= 1;
  259.     }
  260. }
  261.     else if(((m = j | k) & 0xffffffff00000000ll) == 0)
  262. {
  263. /* each value fits in 32 bits, use long word arithmetic */
  264. n = (uint32_t)j/(uint32_t)k;
  265. *pRem = (uint32_t)j - ((uint32_t)n * (uint32_t)k);
  266. }
  267.     else
  268. {
  269. /* not a divide by power of 2 and more than 32 bits */
  270. /* set mask to uppermost byte that is non-zero */
  271. i = 0xff00000000000000ll;
  272. if ((m & i) == 0)
  273.     {
  274.     i >>= 8;
  275.     if ((m & i) == 0)
  276. {
  277. i >>= 8;
  278. if ((m & i) == 0)
  279.     {
  280.     i >>= 8;
  281.     }
  282. }
  283.     }
  284. /* shift the denominator to left until it is greater than
  285.  * the numerator.
  286.  */
  287. c = 0;            /* number of bits the denominator is shifted */
  288. while ((k & i) == 0)
  289.     {
  290.     k <<= 8;
  291.     c += 8;
  292.     }
  293. /* shift single bits until j < k */
  294. if(j & 0x8000000000000000ll)
  295.     {
  296.     while ((k & 0x8000000000000000ll) == 0)
  297. {
  298. k <<= 1;
  299. c++;
  300. }
  301.     n = 0;
  302.     if (j >= k)
  303. {
  304. j -= k;
  305. n |= 1;
  306. }
  307.     }
  308. else
  309.     {
  310.     while (k <= j)
  311. {
  312. k <<= 1;
  313. c++;
  314. }
  315.     n = 0;
  316.     }
  317. /* subtract the shifted denominator from numerator until the result
  318.  * bits are full
  319.  */
  320. while (c-- > 0)
  321.     {
  322.     k >>= 1;
  323.     n <<= 1;
  324.     if (j >= k)
  325. {
  326. j -= k;
  327. n |= 1;
  328. }
  329.     }
  330. /* save the remainder */
  331. *pRem = j;
  332. }
  333.     /* result is stored in n */
  334.     
  335.     *pRes = n;
  336.     }
  337. #ifdef USE_C_MULT64_ROUTINE
  338. /******************************************************************************
  339. *
  340. * tx79Mult64 - perform a 64 bit unsigned multiply
  341. *
  342. * This routine does a 64 bit unsigned multiply and returns the result as
  343. * two 64 bit unsigned integers.  Do not call this routine directly, call
  344. * either tx79dmult or tx79dmultu.
  345. *
  346. * The C compiler will truncate all results to 32 bits.  For this reason,
  347. * 16 bit multiplies must be used.  The 16 bit values will be stored in
  348. * 32 bit integers so that the 32 bit result will not be truncated.
  349. *
  350. * NOMANUAL
  351. */
  352. static void tx79Mult64(uint64_t j,
  353.        uint64_t k,
  354.        uint64_t *pResLow,
  355.        uint64_t *pResHigh)
  356.     {
  357.     uint32_t j0, j1, j2, j3;
  358.     uint32_t k0, k1, k2, k3;
  359.     uint64_t res0, res1, res2;
  360.     /* split up the incoming values */
  361.     j0 = (uint32_t) (j & 0xffff);
  362.     j1 = (uint32_t) ((j >> 16) & 0xffff);
  363.     j2 = (uint32_t) ((j >> 32) & 0xffff);
  364.     j3 = (uint32_t) ((j >> 48) & 0xffff);
  365.     k0 = (uint32_t) (k & 0xffff);
  366.     k1 = (uint32_t) ((k >> 16) & 0xffff);
  367.     k2 = (uint32_t) ((k >> 32) & 0xffff);
  368.     k3 = (uint32_t) ((k >> 48) & 0xffff);
  369.     /* multiply the pieces
  370.      * To keep the resN variables from overflowing while summing,
  371.      * the values added to resN will never be greater than 48 bits.
  372.      * Except for the j3 * k3 product.  If this overflows, the
  373.      * result will overflow.
  374.      */
  375.     /* res0 stores the lower 32 bits of the result */
  376.     
  377.     res0 = (uint64_t) (j0 * k0);
  378.     res0 += (uint64_t) (j0 * k1) << 16;
  379.     res0 += (uint64_t) (j1 * k0) << 16;
  380.     /* res1 stores the second 32 bits of the result
  381.      * it starts out with the overflow from res0
  382.      */
  383.     res1 = (res0 >> 32);
  384.     res1 += (uint64_t) (j1 * k1);
  385.     res1 += (uint64_t) (j0 * k2);
  386.     res1 += (uint64_t) (j2 * k0);
  387.     res1 += (uint64_t) (j1 * k2) << 16;
  388.     res1 += (uint64_t) (j2 * k1) << 16;
  389.     res1 += (uint64_t) (j0 * k3) << 16;
  390.     res1 += (uint64_t) (j3 * k0) << 16;
  391.     /* res2 stores the upper 64 bits of the result
  392.      * it starts out with the overflow from res1
  393.      */
  394.     res2 = (res1 >> 32);
  395.     res2 += (uint64_t) (j2 * k2);
  396.     res2 += (uint64_t) (j1 * k3);
  397.     res2 += (uint64_t) (j3 * k1);
  398.     res2 += (uint64_t) (j2 * k3) << 16;
  399.     res2 += (uint64_t) (j3 * k2) << 16;
  400.     res2 += (uint64_t) (j3 * k3) << 32;
  401.     /* combine and save the results */
  402.     
  403.     *pResLow = (res0 & 0xffffffff) + ((res1 & 0xffffffff) << 32);
  404.     *pResHigh = res2;
  405.     
  406.     }
  407. #endif /* ifdef USE_C_MULT64_ROUTINE */
  408. /******************************************************************************
  409. *
  410. * tx79ddiv - perform a 64 bit signed division
  411. *
  412. * This routine does a 64 bit signed division and returns the result as
  413. * a 64 bit signed result and a 64 bit signed remainder.
  414. *
  415. * NOMANUAL
  416. */
  417. void tx79ddiv(uint64_t j,
  418.       uint64_t k,
  419.       uint64_t* pRes,
  420.       uint64_t* pRem)
  421.     {
  422.     int s;  /* sign of result */
  423.     int ns; /* sign of remainder */
  424.     
  425.     /* make values positive and determine sign of result */
  426.     
  427.     s = 0;
  428.     ns = 0;
  429.     if ((int64_t)j < 0)
  430. {
  431. j = -j;
  432. s ^= 1;
  433. ns = 1;
  434. }
  435.     if ((int64_t)k <= 0)
  436. {
  437. /* handle divide by zero case */
  438. if ((int64_t)k == 0)
  439.     {
  440.     *pRes = s ? 0x8000000000000000ull : 0x7fffffffffffffffull;
  441.     *pRem = 0;
  442.     return;
  443.     }
  444. k = -k;
  445. s ^= 1;
  446. }
  447.     /* use unsigned div routine */
  448.     
  449.     tx79Div64(j, k, pRes, pRem);
  450.     /* modify result back to correct sign */
  451.     *pRes = s ? -(*pRes) : *pRes;
  452.     *pRem = ns ? -(*pRem) : *pRem;
  453. }
  454. /******************************************************************************
  455. *
  456. * tx79ddivu - perform a 64 bit unsigned division
  457. *
  458. * This routine does a 64 bit unsigned division and returns the result as
  459. * a 64 bit unsigned result and a 64 bit unsigned remainder.
  460. *
  461. * NOMANUAL
  462. */
  463. void tx79ddivu(uint64_t j,
  464.        uint64_t k,
  465.        uint64_t* pRes,
  466.        uint64_t* pRem)
  467.     {
  468.     /* handle divide by zero case */
  469.     
  470.     if (k == 0)
  471. {
  472. *pRes = 0;
  473. *pRem = 0;
  474. }
  475.     else
  476. tx79Div64(j, k, pRes, pRem);
  477.     }
  478. /******************************************************************************
  479. *
  480. * tx79dmult - perform a 64 bit signed multiplication
  481. *
  482. * This routine does a 64 bit signed multiplication and returns the result as
  483. * a 128 bit signed result.
  484. *
  485. * NOMANUAL
  486. */
  487. void tx79dmult(uint64_t j,
  488.        uint64_t k,
  489.        uint64_t* pResLow,
  490.        uint64_t* pResHigh)
  491.     {
  492.     int s;
  493.     /* take shortcut if either value is 0 */
  494.     
  495.     if ((j == 0) || (k == 0))
  496. {
  497. *pResLow = 0;
  498. *pResHigh = 0;
  499. }
  500.     else
  501. {
  502. /* make values positive and determine sign of result */
  503.     
  504. s = 0;
  505. if ((int64_t)j < 0)
  506.     {
  507.     j = -j;
  508.     s ^= 1;
  509.     }
  510. if ((int64_t)k < 0)
  511.     {
  512.     k = -k;
  513.     s ^= 1;
  514.     }
  515. /* use unsigned multiply */
  516. #ifdef USE_C_MULT64_ROUTINE
  517. tx79Mult64(j, k, pResLow, pResHigh);
  518. #else  /* ifdef USE_C_MULT64_ROUTINE */
  519. tx79AMult64(j, k, pResLow, pResHigh);
  520. #endif /* ifdef USE_C_MULT64_ROUTINE */
  521. /* modify result back to correct sign */
  522. if (s == 1)
  523.     {
  524.     if (*pResLow != 0)
  525. {
  526. *pResLow = -(*pResLow);
  527. *pResHigh =  ~(*pResHigh);
  528. }
  529.     else
  530. {
  531. *pResHigh =  -(*pResHigh);
  532. }
  533.     }
  534. }
  535.     }
  536. /******************************************************************************
  537. *
  538. * tx79dmultu - perform a 64 bit unsigned multiplication
  539. *
  540. * This routine does a 64 bit unsigned multiplication and returns the result as
  541. * a 128 bit unsigned result.
  542. *
  543. * NOMANUAL
  544. */
  545. void tx79dmultu(uint64_t j,
  546.        uint64_t k,
  547.        uint64_t* pResLow,
  548.        uint64_t* pResHigh)
  549.     {
  550.     if ((k == 0) || (j == 0))
  551. {
  552. *pResLow = 0;
  553. *pResHigh = 0;
  554. }
  555.     else
  556. #ifdef USE_C_MULT64_ROUTINE
  557. tx79Mult64(j, k, pResLow, pResHigh);
  558. #else  /* ifdef USE_C_MULT64_ROUTINE */
  559. tx79AMult64(j, k, pResLow, pResHigh);
  560. #endif /* ifdef USE_C_MULT64_ROUTINE */
  561.     }
  562. #endif /* (CPU == MIPS64) */