summaryrefslogtreecommitdiff
path: root/tests/tst-bswap.c
blob: aff9cbd31347324b3c164052c32dc00cdd63d19c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <stdio.h>
#include <string.h>
#include <libmcpu.h>
#include "../utils/mcpu-asm.h"

#define CHECK(c,m) do{if(!(c)){fprintf(stderr,"FAIL: %s\n",m);return 1;}}while(0)

static void
regop( cpu_operand *o, unsigned bits, unsigned address )
{
  memset( o, 0, sizeof( *o ) );
  o->type = CPU_OPERAND_REGISTER;
  o->value.reg.bits = bits;
  o->value.reg.address = address;
}

static int
do_bswap( unsigned bits, unsigned d, unsigned s )
{
  cpu_instruction i;
  memset( &i, 0, sizeof( i ) );
  i.opcode = CPU_OP_BSWAP;
  regop( &i.operand[0], bits, d );
  regop( &i.operand[1], bits, s );
  return( __cpu_exec( &i ) );
}

int
main( void )
{
  cpu_asm_image im;
  char err[256];
  __mpu_UNIT_t *src, *dst;
  unsigned i;
  __mpu_uint32_t psw;
  const char *asrc=
    ".text\n"
    "LDI r64@0x00000, 42\n"
    "BSWAP r64@0x00008, r64@0x00000\n"
    "BSWAP r64@0x00010, r64@0x00008\n"
    "HALT\n";

  __cpu_init();
  CHECK( cpu_assemble_text( asrc, &im, err, sizeof( err ) ) == 0, err );
  CHECK( im.code_size == 31, "BSWAP machine size is OPCODE16 + 2*REG24" );
  CHECK( __cpu_code_get_u16( im.code + 13 ) == CPU_OP_BSWAP, "first BSWAP opcode encoded" );
  CHECK( __cpu_program_set( im.code, im.code_size ) == 0, "set BSWAP program" );
  CHECK( __cpu_run() == CPU_EXEC_SUCCESS, "run BSWAP program" );
  CHECK( __cpu_data_get_u64( __cpu_reg_ptr( 64, 0x10 ) ) == 42, "double BSWAP round trip" );
  cpu_asm_image_free( &im );

  /* r8 is a defined identity operation. */
  src = __cpu_reg_ptr( 8, 0x100 );
  dst = __cpu_reg_ptr( 8, 0x101 );
  *src = 0xa5;
  *dst = 0;
  CHECK( do_bswap( 8, 0x101, 0x100 ) == CPU_EXEC_SUCCESS, "BSWAP r8" );
  CHECK( *dst == 0xa5, "BSWAP r8 identity" );

  /* Arbitrary wide physical registers are reversed byte for byte. */
  src = __cpu_reg_ptr( 256, 0x200 );
  dst = __cpu_reg_ptr( 256, 0x220 );
  for( i = 0; i < 32; i++ ) src[i] = (__mpu_UNIT_t)i;
  memset( dst, 0, 32 );
  psw = PSW_CF_MASK | PSW_IF_MASK | PSW_TF_MASK;
  __cpu_set_psw( psw );
  CHECK( do_bswap( 256, 0x220, 0x200 ) == CPU_EXEC_SUCCESS, "BSWAP r256" );
  for( i = 0; i < 32; i++ ) CHECK( dst[i] == (__mpu_UNIT_t)( 31 - i ), "BSWAP r256 byte reversal" );
  CHECK( __cpu_get_psw() == psw, "BSWAP preserves PSW" );

  /* In-place BSWAP uses source-snapshot semantics. */
  src = __cpu_reg_ptr( 64, 0x300 );
  for( i = 0; i < 8; i++ ) src[i] = (__mpu_UNIT_t)( 0x10 + i );
  CHECK( do_bswap( 64, 0x300, 0x300 ) == CPU_EXEC_SUCCESS, "in-place BSWAP" );
  for( i = 0; i < 8; i++ ) CHECK( src[i] == (__mpu_UNIT_t)( 0x17 - i ), "in-place BSWAP snapshot result" );

  /* Maximum physical width is supported. */
  src = __cpu_reg_ptr( 65536, 0x0000 );
  dst = __cpu_reg_ptr( 65536, 0x2000 );
  for( i = 0; i < 8192; i++ ) src[i] = (__mpu_UNIT_t)( i & 0xffU );
  CHECK( do_bswap( 65536, 0x2000, 0x0000 ) == CPU_EXEC_SUCCESS, "BSWAP r65536" );
  CHECK( dst[0] == src[8191] && dst[8191] == src[0], "BSWAP r65536 endpoints" );

  /* Width mismatch is rejected before modifying destination. */
  {
    cpu_instruction x;
    __mpu_UNIT_t before[8];
    memset( x.operand, 0, sizeof( x.operand ) );
    x.opcode = CPU_OP_BSWAP;
    regop( &x.operand[0], 64, 0x400 );
    regop( &x.operand[1], 32, 0x408 );
    memset( __cpu_reg_ptr( 64, 0x400 ), 0x5a, 8 );
    memcpy( before, __cpu_reg_ptr( 64, 0x400 ), 8 );
    CHECK( __cpu_exec( &x ) == CPU_EXEC_WIDTH_FAULT, "BSWAP width mismatch" );
    CHECK( memcmp( before, __cpu_reg_ptr( 64, 0x400 ), 8 ) == 0, "BSWAP width fault atomic" );
  }

  /* Assembler syntax intentionally uses raw r<bits> views, not c<bits>. */
  CHECK( cpu_assemble_text( ".text\nBSWAP c64@0x0, c64@0x8\nHALT\n", &im, err, sizeof( err ) ) != 0,
        "assembler rejects complex spelling for raw BSWAP");

  __cpu_free_context();
  puts( "libcpu BSWAP regression: PASS" );
  return( 0 );
}