/examples/bench/main.c
#include <stdio.h>
#include <dos.h>
#include <conio.h>
#include <alloc.h>
#include <mem.h>

#include "i89.h"

extern i89_task_block tb_memcpy_mov, tb_memcpy_mov16, tb_memcpy_xfer, tb_memcpy_xfer16;

struct memcpy_parameter_block {
	i89_channel_parameter_block_t cpb;
	unsigned int far * src;
	unsigned int far * dest;
	unsigned int count;
};

struct i89_channel far * ccb;
struct memcpy_parameter_block memcpy_pb = { 0 };

unsigned long int st_to_ticks(const struct time *t) {
	return t->ti_hour * 360000 + t->ti_min * 6000 + t->ti_sec * 100 + t->ti_hund;
}

void memcpy_naive(void * dest, const void * src, size_t n) {
	char * d = dest;
	char * s = src;
	while (n > 0) {
		*d = *s;
		d++;
		s++;
		n--;
	}
}

void memcpy_naive16(void * dest, const void * src, size_t n) {
	int * d = dest;
	int * s = src;
	n >>= 1;
	while (n > 0) {
		*d = *s;
		d++;
		s++;
		n--;
	}
}

void memcpy_i89(void * dest, const void * src, size_t n) {
	memcpy_pb.cpb.tbp = &tb_memcpy_mov;
	ccb[1].ccw = 0x03;
	ccb[1].ppb = &memcpy_pb.cpb;
	memcpy_pb.src = src;
	memcpy_pb.dest = dest;
	memcpy_pb.count = n;
	outportb(0x72, 0);
}

void memcpy_i89_16(void * dest, const void * src, size_t n) {
	memcpy_pb.cpb.tbp = &tb_memcpy_mov16;
	ccb[1].ccw = 0x03;
	ccb[1].ppb = &memcpy_pb.cpb;
	memcpy_pb.src = src;
	memcpy_pb.dest = dest;
	memcpy_pb.count = n >> 1;
	outportb(0x72, 0);
}

void memcpy_i89_xfer(void * dest, const void * src, size_t n) {
	memcpy_pb.cpb.tbp = &tb_memcpy_xfer;
	ccb[1].ccw = 0x03;
	ccb[1].ppb = &memcpy_pb.cpb;
	memcpy_pb.src = src;
	memcpy_pb.dest = dest;
	memcpy_pb.count = n;
	outportb(0x72, 0);
}

void memcpy_i89_xfer_16(void * dest, const void * src, size_t n) {
	memcpy_pb.cpb.tbp = &tb_memcpy_xfer16;
	ccb[1].ccw = 0x03;
	ccb[1].ppb = &memcpy_pb.cpb;
	memcpy_pb.src = src;
	memcpy_pb.dest = dest;
	memcpy_pb.count = n;
	outportb(0x72, 0);
}

void test_done(void * b1, void * b2, size_t len, const struct time * t0,
               const struct time * t1, const char *test_name) {
	long int t_acc = st_to_ticks(t1) - st_to_ticks(t0);
	printf("%-20s%ld.%ld ticks\n", test_name, t_acc / 10, t_acc % 10);
	if (memcmp(b1, b2, len) != 0) {
		printf("data compare error\n");
		exit(1);
	}
	memset(b2, 0, len);
}

void main() {
	long int i;
	size_t copy_len = 32768;
	struct time t0, t1;
	char far * buffer1;
	char far * buffer2;

	buffer1 = farmalloc(copy_len);
	printf("buffer1: %Fp\n", buffer1);
	if (buffer1 == NULL) {
		printf("Could not allocate buffer1\n");
		return;
	}
	buffer2 = farmalloc(copy_len);
	printf("buffer2: %Fp\n", buffer2);
	if (buffer2 == NULL) {
		printf("Could not allocate buffer2\n");
		return;
	}
	ccb = MK_FP(0x0000, 0x0500);

	for (i = 0; i < copy_len; i++) {
		buffer1[i] = (unsigned char)i;
	}

	gettime(&t0);
	memcpy(buffer2, buffer1, copy_len);
	memcpy(buffer2, buffer1, copy_len);
	memcpy(buffer2, buffer1, copy_len);
	memcpy(buffer2, buffer1, copy_len);
	memcpy(buffer2, buffer1, copy_len);
	memcpy(buffer2, buffer1, copy_len);
	memcpy(buffer2, buffer1, copy_len);
	memcpy(buffer2, buffer1, copy_len);
	memcpy(buffer2, buffer1, copy_len);
	memcpy(buffer2, buffer1, copy_len);
	gettime(&t1);
	test_done(buffer1, buffer2, copy_len, &t0, &t1, "memcpy");

	gettime(&t0);
	memcpy_naive(buffer2, buffer1, copy_len);
	memcpy_naive(buffer2, buffer1, copy_len);
	memcpy_naive(buffer2, buffer1, copy_len);
	memcpy_naive(buffer2, buffer1, copy_len);
	memcpy_naive(buffer2, buffer1, copy_len);
	memcpy_naive(buffer2, buffer1, copy_len);
	memcpy_naive(buffer2, buffer1, copy_len);
	memcpy_naive(buffer2, buffer1, copy_len);
	memcpy_naive(buffer2, buffer1, copy_len);
	memcpy_naive(buffer2, buffer1, copy_len);
	gettime(&t1);
	test_done(buffer1, buffer2, copy_len, &t0, &t1, "memcpy_naive");

	gettime(&t0);
	memcpy_naive16(buffer2, buffer1, copy_len);
	memcpy_naive16(buffer2, buffer1, copy_len);
	memcpy_naive16(buffer2, buffer1, copy_len);
	memcpy_naive16(buffer2, buffer1, copy_len);
	memcpy_naive16(buffer2, buffer1, copy_len);
	memcpy_naive16(buffer2, buffer1, copy_len);
	memcpy_naive16(buffer2, buffer1, copy_len);
	memcpy_naive16(buffer2, buffer1, copy_len);
	memcpy_naive16(buffer2, buffer1, copy_len);
	memcpy_naive16(buffer2, buffer1, copy_len);
	gettime(&t1);
	test_done(buffer1, buffer2, copy_len, &t0, &t1, "memcpy_naive16");

	gettime(&t0);
	memcpy_i89(buffer2, buffer1, copy_len);
	memcpy_i89(buffer2, buffer1, copy_len);
	memcpy_i89(buffer2, buffer1, copy_len);
	memcpy_i89(buffer2, buffer1, copy_len);
	memcpy_i89(buffer2, buffer1, copy_len);
	memcpy_i89(buffer2, buffer1, copy_len);
	memcpy_i89(buffer2, buffer1, copy_len);
	memcpy_i89(buffer2, buffer1, copy_len);
	memcpy_i89(buffer2, buffer1, copy_len);
	memcpy_i89(buffer2, buffer1, copy_len);
	gettime(&t1);
	test_done(buffer1, buffer2, copy_len, &t0, &t1, "memcpy_i89_mov");

	gettime(&t0);
	memcpy_i89_16(buffer2, buffer1, copy_len);
	memcpy_i89_16(buffer2, buffer1, copy_len);
	memcpy_i89_16(buffer2, buffer1, copy_len);
	memcpy_i89_16(buffer2, buffer1, copy_len);
	memcpy_i89_16(buffer2, buffer1, copy_len);
	memcpy_i89_16(buffer2, buffer1, copy_len);
	memcpy_i89_16(buffer2, buffer1, copy_len);
	memcpy_i89_16(buffer2, buffer1, copy_len);
	memcpy_i89_16(buffer2, buffer1, copy_len);
	memcpy_i89_16(buffer2, buffer1, copy_len);
	gettime(&t1);
	test_done(buffer1, buffer2, copy_len, &t0, &t1, "memcpy_i89_mov16");

	gettime(&t0);
	memcpy_i89_xfer(buffer2, buffer1, copy_len);
	memcpy_i89_xfer(buffer2, buffer1, copy_len);
	memcpy_i89_xfer(buffer2, buffer1, copy_len);
	memcpy_i89_xfer(buffer2, buffer1, copy_len);
	memcpy_i89_xfer(buffer2, buffer1, copy_len);
	memcpy_i89_xfer(buffer2, buffer1, copy_len);
	memcpy_i89_xfer(buffer2, buffer1, copy_len);
	memcpy_i89_xfer(buffer2, buffer1, copy_len);
	memcpy_i89_xfer(buffer2, buffer1, copy_len);
	memcpy_i89_xfer(buffer2, buffer1, copy_len);
	gettime(&t1);
	test_done(buffer1, buffer2, copy_len, &t0, &t1, "memcpy_i89_xfer");

	gettime(&t0);
	memcpy_i89_xfer_16(buffer2, buffer1, copy_len);
	memcpy_i89_xfer_16(buffer2, buffer1, copy_len);
	memcpy_i89_xfer_16(buffer2, buffer1, copy_len);
	memcpy_i89_xfer_16(buffer2, buffer1, copy_len);
	memcpy_i89_xfer_16(buffer2, buffer1, copy_len);
	memcpy_i89_xfer_16(buffer2, buffer1, copy_len);
	memcpy_i89_xfer_16(buffer2, buffer1, copy_len);
	memcpy_i89_xfer_16(buffer2, buffer1, copy_len);
	memcpy_i89_xfer_16(buffer2, buffer1, copy_len);
	memcpy_i89_xfer_16(buffer2, buffer1, copy_len);
	gettime(&t1);
	test_done(buffer1, buffer2, copy_len, &t0, &t1, "memcpy_i89_xfer16");

	printf("Looping tests...\n");

	while (1) {
		outportb(0x48, 0x01);
		memcpy(buffer2, buffer1, copy_len);
		outportb(0x48, 0);

		outportb(0x48, 0x02);
		memcpy_naive(buffer2, buffer1, copy_len);
		outportb(0x48, 0);

		outportb(0x48, 0x04);
		memcpy_naive16(buffer2, buffer1, copy_len);
		outportb(0x48, 0);

		outportb(0x48, 0x10);
		memcpy_i89(buffer2, buffer1, copy_len);
		outportb(0x48, 0);

		outportb(0x48, 0x20);
		memcpy_i89_16(buffer2, buffer1, copy_len);
		outportb(0x48, 0);

		outportb(0x48, 0x40);
		memcpy_i89_xfer(buffer2, buffer1, copy_len);
		outportb(0x48, 0);

		outportb(0x48, 0x80);
		memcpy_i89_xfer_16(buffer2, buffer1, copy_len);
		outportb(0x48, 0);

		kbhit();
	}
}