File:  [Isaki's NoNo m68k/m88k emulator] / nono / vm / test_ethernet.cpp
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:06:00 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, HEAD
nono 1.7.0

//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//

// EthernetDevice::CRC32() のテスト。

#include "header.h"
#include "bitops.h"
#include "macaddr.h"
#include "stopwatch.h"
#include <signal.h>
#include <sys/time.h>

// パフォーマンステストの秒数
#define PERF_SEC	(2)

class EthernetDevice
{
 public:
	static uint32 CRC32(const uint8 *buf, size_t buflen);
	static uint32 CRC32(const MacAddr& mac);
};

#define SELFTEST
#include "ethernet.cpp"

// testnum は 0 が通常の CRC、1 が MAC アドレス用 CRC。
static void
do_test(int testnum)
{
	struct {
		uint8 src[6];
		uint32 expected;
	} table[] = {
		{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },	0x3a7abc72 },
		{ { 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 },	0xf99baaba },
	};
	int failed = 0;

	if (testnum == 0) {
		printf("Test(buf)");
	} else {
		printf("Test(mac)");
	}

	for (size_t i = 0; i < countof(table); i++) {
		const uint8 *src = table[i].src;
		uint32 expected  = table[i].expected;
		uint32 actual;
		if (testnum == 0) {
			actual = EthernetDevice::CRC32(src, 6);
		} else {
			MacAddr mac(src);
			actual = EthernetDevice::CRC32(mac);
		}

		if (actual != expected) {
			if (failed == 0) {
				printf("\n");
			}
			printf("FAILED: %02x%02x%02x%02x%02x%02x expects %08x but got %08x",
				src[0], src[1], src[2], src[3], src[4], src[5],
				expected, actual);

			// 念のため反転して一致するか。
			uint32 revact = bitrev32(actual);
			if (revact == expected) {
				printf(" (bit-reversed)");
			}

			printf(" !\n");
			failed++;
		}
	}
	if (failed == 0) {
		printf("..OK\n");
	}
}

static volatile uint32 perf_signaled;
static uint64 perf_count;
static Stopwatch sw;

static void
signal_alarm(int signo)
{
	perf_signaled = 1;
}

static void
start_perf_func(const char *name)
{
	printf("%s\t... ", name);
	fflush(stdout);

	perf_count = 0;
	perf_signaled = 0;
	signal(SIGALRM, signal_alarm);
	struct itimerval it = {};
	it.it_value.tv_sec = PERF_SEC;

	sw.Restart();
	setitimer(ITIMER_REAL, &it, NULL);
}

static void
end_perf_func()
{
	sw.Stop();

	uint64 usec = nsec_to_usec(sw.Elapsed_nsec());
	printf("%6.2f times/usec\n", (double)perf_count / usec);
}

// ターゲット長がMACアドレスで従来の CRC32(buf)。
static void
do_perf_mac_old()
{
	union {
		uint8 buf[6];
		uint32 u32;
	};

	memset(buf, 0, sizeof(buf));
	start_perf_func("macaddr.old");
	while (perf_signaled == 0) {
		volatile uint32 crc;
		crc = EthernetDevice::CRC32(buf, sizeof(buf));
		perf_count++;
		u32 = crc;
	}
	end_perf_func();
}

// ターゲット長がMACアドレスで CRC32(mac)。
static void
do_perf_mac_new()
{
	union {
		uint8 buf[6];
		uint32 u32;
	};

	memset(buf, 0, sizeof(buf));
	MacAddr mac(buf);
	start_perf_func("macaddr.new");
	while (perf_signaled == 0) {
		volatile uint32 crc;
		crc = EthernetDevice::CRC32(mac);
		perf_count++;
		u32 = crc;
	}
	end_perf_func();
}

// ターゲット長が1500バイトの場合。
static void
do_perf_buf()
{
	union {
		uint8 buf[1500];
		uint32 u32;
	};

	memset(buf, 0, sizeof(buf));
	start_perf_func("1500bytes");
	while (perf_signaled == 0) {
		uint32 crc;
		crc = EthernetDevice::CRC32(buf, sizeof(buf));
		perf_count++;
		u32 = crc;
	}
	end_perf_func();
}

int
main(int ac, char *av[])
{
	do_test(0);
	do_test(1);
	do_perf_buf();
	do_perf_mac_old();
	do_perf_mac_new();
	return 0;
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.