142d6ce6817bb4cfc9c0284f136592f6c55568bf7florian#include <stdint.h>
242d6ce6817bb4cfc9c0284f136592f6c55568bf7florian#include <inttypes.h>
342d6ce6817bb4cfc9c0284f136592f6c55568bf7florian#include <stdlib.h>
442d6ce6817bb4cfc9c0284f136592f6c55568bf7florian#include <string.h>
542d6ce6817bb4cfc9c0284f136592f6c55568bf7florian#include <stdio.h>
642d6ce6817bb4cfc9c0284f136592f6c55568bf7florian#include "opcodes.h"
742d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
842d6ce6817bb4cfc9c0284f136592f6c55568bf7florian#ifndef M3
942d6ce6817bb4cfc9c0284f136592f6c55568bf7florian#define M3 0
1042d6ce6817bb4cfc9c0284f136592f6c55568bf7florian#endif
1142d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
1242d6ce6817bb4cfc9c0284f136592f6c55568bf7florian/* The abstracted result of an CU24 insn */
1342d6ce6817bb4cfc9c0284f136592f6c55568bf7floriantypedef struct {
1442d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   uint64_t addr1;  // target
1542d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   uint64_t len1;
1642d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   uint64_t addr2;  // source
1742d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   uint64_t len2;
1842d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   uint32_t cc;
1942d6ce6817bb4cfc9c0284f136592f6c55568bf7florian} cu24_t;
2042d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
2142d6ce6817bb4cfc9c0284f136592f6c55568bf7florian/* Define various input buffers. */
2242d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
2342d6ce6817bb4cfc9c0284f136592f6c55568bf7florian/* Single UTF-16 value */
2442d6ce6817bb4cfc9c0284f136592f6c55568bf7florianuint16_t pattern1[] = {
2542d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   0x0000, 0xd7ff,    /* [0000 ... d7ff]  corner cases */
2642d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   0xdc00, 0xffff,    /* [dc00 ... ffff]  corner cases */
2742d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   0x0047, 0x0156, 0x1245, 0xa021, 0xfffe /* misc */
2842d6ce6817bb4cfc9c0284f136592f6c55568bf7florian};
2942d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
3042d6ce6817bb4cfc9c0284f136592f6c55568bf7florian/* UTF-16 surrogate pair */
3142d6ce6817bb4cfc9c0284f136592f6c55568bf7florianuint16_t pattern2[] = {
3242d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   0xd800, 0xdc00,    /* left  corner case */
3342d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   0xdbff, 0xdfff,    /* right corner case */
3442d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   0xdada, 0xdddd, 0xdeaf, 0xdcdc  /* misc */
3542d6ce6817bb4cfc9c0284f136592f6c55568bf7florian};
3642d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
3742d6ce6817bb4cfc9c0284f136592f6c55568bf7florian/* Invalid low surrogate */
3842d6ce6817bb4cfc9c0284f136592f6c55568bf7florianuint16_t invalid[] = { 0xd801, 0x0098 };
3942d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
4042d6ce6817bb4cfc9c0284f136592f6c55568bf7florian/* Mixed bytes */
4142d6ce6817bb4cfc9c0284f136592f6c55568bf7florianuint16_t mixed[] = {
4242d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   0x0078,
4342d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   0x0200,
4442d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   0xffff,
4542d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   0xd800, 0xdc01,
4642d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   0xde00, 0xdd00,
4742d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   0xc0c0
4842d6ce6817bb4cfc9c0284f136592f6c55568bf7florian};
4942d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
5042d6ce6817bb4cfc9c0284f136592f6c55568bf7florian/* This is the buffer for the converted bytes. */
5142d6ce6817bb4cfc9c0284f136592f6c55568bf7florianuint32_t buff[1000];  /* Large so we con'don't have to worry about it */
5242d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
5342d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
5442d6ce6817bb4cfc9c0284f136592f6c55568bf7florianstatic cu24_t
5542d6ce6817bb4cfc9c0284f136592f6c55568bf7floriando_cu24(uint32_t *dst, uint64_t dst_len, uint16_t *src, uint64_t src_len)
5642d6ce6817bb4cfc9c0284f136592f6c55568bf7florian{
5742d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   int cc = 42;
5842d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   cu24_t regs;
5942d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
6042d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   /* build up the register pairs */
6142d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   register uint16_t *source     asm("4") = src;
6242d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   register uint64_t  source_len asm("5") = src_len;
6342d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   register uint32_t *dest       asm("2") = dst;
6442d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   register uint64_t  dest_len   asm("3") = dst_len;
6542d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
6642d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   asm volatile(
6742d6ce6817bb4cfc9c0284f136592f6c55568bf7florian                CU24(M3,2,4)
6842d6ce6817bb4cfc9c0284f136592f6c55568bf7florian                "ipm %2\n\t"
6942d6ce6817bb4cfc9c0284f136592f6c55568bf7florian                "srl %2,28\n\t"
7042d6ce6817bb4cfc9c0284f136592f6c55568bf7florian                : "+d"(dest), "+d"(source), "=d"(cc),
7142d6ce6817bb4cfc9c0284f136592f6c55568bf7florian                  "+d"(source_len), "+d"(dest_len)
7242d6ce6817bb4cfc9c0284f136592f6c55568bf7florian                :
7342d6ce6817bb4cfc9c0284f136592f6c55568bf7florian                : "memory", "cc");
7442d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
7542d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   /* Capture register contents at end of cu24 */
7642d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   regs.addr1 = (uint64_t)dest;
7742d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   regs.len1  = dest_len;
7842d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   regs.addr2 = (uint64_t)source;
7942d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   regs.len2  = source_len;
8042d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   regs.cc = cc;
8142d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
8242d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   return regs;
8342d6ce6817bb4cfc9c0284f136592f6c55568bf7florian}
8442d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
8542d6ce6817bb4cfc9c0284f136592f6c55568bf7florianvoid
8642d6ce6817bb4cfc9c0284f136592f6c55568bf7florianrun_test(uint32_t *dst, uint64_t dst_len, uint16_t *src, uint64_t src_len)
8742d6ce6817bb4cfc9c0284f136592f6c55568bf7florian{
8842d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   int i;
8942d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   cu24_t result;
9042d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
9142d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   result = do_cu24(dst, dst_len, src, src_len);
9242d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
9342d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   // Write out the converted byte, if any
9442d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   printf("UTF32: ");
9542d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   if (dst_len - result.len1 == 0)
9642d6ce6817bb4cfc9c0284f136592f6c55568bf7florian      printf(" <none>");
9742d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   else {
9842d6ce6817bb4cfc9c0284f136592f6c55568bf7florian      uint64_t num_bytes = dst_len - result.len1;
9942d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
10042d6ce6817bb4cfc9c0284f136592f6c55568bf7florian      /* The number of bytes that were written must be divisible by 4 */
10142d6ce6817bb4cfc9c0284f136592f6c55568bf7florian      if (num_bytes % 4 != 0)
10242d6ce6817bb4cfc9c0284f136592f6c55568bf7florian         fprintf(stderr, "*** number of bytes is not a multiple of 4\n");
10342d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
10442d6ce6817bb4cfc9c0284f136592f6c55568bf7florian      for (i = 0; i < num_bytes / 4; i++) {
10542d6ce6817bb4cfc9c0284f136592f6c55568bf7florian         printf(" %02x", dst[i]);
10642d6ce6817bb4cfc9c0284f136592f6c55568bf7florian      }
10742d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   }
10842d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   printf("\n");
10942d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
11042d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   printf("  cc = %d\n", result.cc);
11142d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   if (dst != NULL)
11242d6ce6817bb4cfc9c0284f136592f6c55568bf7florian      printf("  dst address difference: %"PRId64, result.addr1 - (uint64_t)dst);
11342d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   printf("  dst len: %"PRId64"\n", result.len1);
11442d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
11542d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   if (src != NULL)
11642d6ce6817bb4cfc9c0284f136592f6c55568bf7florian      printf("  src address difference: %"PRId64, result.addr2 - (uint64_t)src);
11742d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   printf("  src len: %"PRId64"\n", result.len2);
11842d6ce6817bb4cfc9c0284f136592f6c55568bf7florian}
11942d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
12042d6ce6817bb4cfc9c0284f136592f6c55568bf7florianint main()
12142d6ce6817bb4cfc9c0284f136592f6c55568bf7florian{
12242d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   /* Length == 0, no memory should be read or written */
12342d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   printf("\n------------- test1 ----------------\n");
12442d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(NULL, 0, NULL, 0);
12542d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
12642d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   /* Test exhaustion of source length (source bytes are valid) */
12742d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   printf("\n------------- test2.1 ----------------\n");
12842d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
12942d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   /* No character will be written to BUFF, i.e. loop in jitted code
13042d6ce6817bb4cfc9c0284f136592f6c55568bf7florian      is not iterated */
13142d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(buff, sizeof buff, NULL,     1);
13242d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(buff, sizeof buff, pattern1, 1);
13342d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(buff, sizeof buff, pattern2, 1);
13442d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(buff, sizeof buff, pattern2, 2);
13542d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(buff, sizeof buff, pattern2, 3);
13642d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
13742d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   printf("\n------------- test2.2 ----------------\n");
13842d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   /* At least one character will be written to BUFF, i.e. loop in jitted
13942d6ce6817bb4cfc9c0284f136592f6c55568bf7florian      code is iterated */
14042d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(buff, sizeof buff, pattern1, 3);
14142d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(buff, sizeof buff, pattern1, 5);
14242d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(buff, sizeof buff, pattern2, 2);
14342d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(buff, sizeof buff, pattern2, 5);
14442d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(buff, sizeof buff, pattern2, 7);
14542d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
14642d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   /* Test exhaustion of destination length (source bytes are valid) */
14742d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   printf("\n------------- test3.1 ----------------\n");
14842d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
14942d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   /* No character will be written to BUFF, i.e. loop in jitted code
15042d6ce6817bb4cfc9c0284f136592f6c55568bf7florian      is not iterated */
15142d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
15242d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   /* Want to write 4 bytes at a time */
15342d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(NULL, 0, pattern1, sizeof pattern1);
15442d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(NULL, 1, pattern1, sizeof pattern1);
15542d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(NULL, 2, pattern1, sizeof pattern1);
15642d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(NULL, 3, pattern1, sizeof pattern1);
15742d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
15842d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   printf("\n------------- test3.2 ----------------\n");
15942d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   /* At least one character will be written to BUFF, i.e. loop in jitted
16042d6ce6817bb4cfc9c0284f136592f6c55568bf7florian      code is iterated */
16142d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(buff, 4, pattern1, sizeof pattern1);
16242d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(buff, 5, pattern1, sizeof pattern1);
16342d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(buff, 6, pattern1, sizeof pattern1);
16442d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(buff, 7, pattern1, sizeof pattern1);
16542d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
16642d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   /* When both operands are exhausted, cc=0 takes precedence.
16742d6ce6817bb4cfc9c0284f136592f6c55568bf7florian      (test1 tests this for len == 0) */
16842d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   printf("\n------------- test4 ----------------\n");
16942d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(buff, 4, pattern1, 2);   // no iteration
17042d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(buff, 8, pattern1, 4);   // iteration
17142d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
17242d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   /* Input has invalid low surrogate. */
17342d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   printf("\n------------- test5 ----------------\n");
17442d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(buff, sizeof buff, invalid, sizeof invalid);
17542d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(buff, 0, invalid, sizeof invalid);
17642d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
17742d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   /* Convert all pattern buffers */
17842d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   printf("\n------------- test6 ----------------\n");
17942d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(buff, sizeof buff, pattern1, sizeof pattern1);
18042d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   run_test(buff, sizeof buff, pattern2, sizeof pattern2);
18142d6ce6817bb4cfc9c0284f136592f6c55568bf7florian
18242d6ce6817bb4cfc9c0284f136592f6c55568bf7florian   return 0;
18342d6ce6817bb4cfc9c0284f136592f6c55568bf7florian}
184