/* * tcpstream.c -- measure the firmware's TCP receive throughput. * * The terminal is the server: socket(SOCK_STREAM) -> bind -> listen -> accept, * then read() into a buffer and copy the bytes into video RAM in order. One * read() can return a whole socket-buffer's worth of bytes, so this can beat * the per-datagram recvfrom cost -- by how much is the question. * * Host-written cells (before the load): * 0x018C9000 byte limit (0 = unlimited) * 0x018C9040 TCP port (0 = 7009) * * Markers at 0x018C8000: * +0x000 stage: 1 entered, 2 socket, 3 bound, 4 listening, 5 accepted, * 0xEE socket failed, 0xEF bind failed, 0xF0 listen failed, * 0xF1 accept failed * +0x020 fd, +0x040 bind ret, +0x060 listen ret, +0x080 accept ret * +0x0A0 reads, +0x0C0 bytes read, +0x0E0 last read length, +0x100 port */ #include "romapi.h" #define VRAM_BASE 0x04000000 #define VRAM_BYTES 0x40000 /* 256 KiB, the real unit's framebuffer */ #define PORT 7009 #define MARK 0x018C8000 #define LIMIT_CELL 0x018C9000 #define PORT_CELL 0x018C9040 static unsigned char sa[16]; static unsigned char from[16]; static unsigned char buf[1472]; static void cell(off, v) unsigned int off, v; { *(unsigned int *)(MARK + off) = v; } static unsigned int getcell(off) unsigned int off; { return *(unsigned int *)(MARK + off); } int main() { int fd, cfd, n, r; unsigned int limit, port, off, total, reads, i; cell(0x000, 1); limit = *(unsigned int *)LIMIT_CELL; port = *(unsigned int *)PORT_CELL; if (port == 0) { port = PORT; } cell(0x100, port); /* per-process user area is uninitialised (see udpstream.c) */ { unsigned int proc, user, k; proc = *(unsigned int *)0x1B3900; user = *(unsigned int *)(proc + 0x100); for (k = 0; k < 0x100; k++) { *(unsigned char *)(user + k * 8) = 0; } cell(0x140, user); } fd = socket_(AF_INET, SOCK_STREAM, 0); cell(0x020, fd); if (fd < 0) { cell(0x000, 0xEE); return 1; } cell(0x000, 2); sa_any(sa, port); r = bind_(fd, sa, SOCKADDR_LEN); cell(0x040, r); if (r < 0) { cell(0x000, 0xEF); close_(fd); return 2; } cell(0x000, 3); r = listen_(fd, 1); cell(0x060, r); if (r < 0) { cell(0x000, 0xF0); close_(fd); return 3; } cell(0x000, 4); cfd = accept_(fd, 0, 0); cell(0x080, cfd); if (cfd < 0) { cell(0x000, 0xF1); close_(fd); return 4; } cell(0x000, 5); cell(0x0A0, 0); cell(0x0C0, 0); off = 0; total = 0; reads = 0; for (;;) { n = read_(cfd, buf, sizeof(buf)); cell(0x0E0, (unsigned int)n); if (n <= 0) { close_(cfd); close_(fd); return 5; } for (i = 0; i < (unsigned int)n; i++) { *(unsigned char *)(VRAM_BASE + off * 8) = buf[i]; off = off + 1; if (off >= VRAM_BYTES) { off = 0; } } total = total + (unsigned int)n; reads = reads + 1; cell(0x0A0, reads); cell(0x0C0, total); if (limit != 0 && total >= limit) { close_(cfd); close_(fd); return 0; } } }