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 );
}
|