mirror of
https://git.k-space.ee/arti/vt1200.git
synced 2026-11-02 12:23:17 +02:00
280 lines
6.9 KiB
C
280 lines
6.9 KiB
C
/* main.c -- Bad Apple payload: network receive, then tile playback. */
|
|
#include "movie.h"
|
|
#include "romapi.h"
|
|
#include "modecfg.h"
|
|
|
|
#ifndef NET_DEFAULT
|
|
#define NET_DEFAULT 0
|
|
#endif
|
|
|
|
#define NET_LEN 2401942
|
|
#define NET_PORT 7001
|
|
|
|
#define MOVIE_BASE 0x00080000
|
|
#define MOVIE_MAX 0x00308000
|
|
#define VRAM_BASE 0x04000000
|
|
#define ROW_BITS 2048
|
|
|
|
/* The marker/control block lives in .bss, not at bit 0x01810000: a 2.4 MB
|
|
* heap allocation can cross that address and would corrupt the movie. */
|
|
unsigned int marker_page[16];
|
|
#define MARK ((unsigned int)marker_page)
|
|
#define CTRL_START (MARK + 0x20 * 8)
|
|
#define CTRL_COUNT (MARK + 0x24 * 8)
|
|
#define CTRL_PACE (MARK + 0x28 * 8)
|
|
#define CTRL_MOVIE (MARK + 0x2C * 8)
|
|
#define CTRL_MOVIELEN (MARK + 0x30 * 8)
|
|
#define CTRL_WAIT (MARK + 0x34 * 8)
|
|
#define CTRL_READY (MARK + 0x38 * 8)
|
|
#define CTRL_NET (MARK + 0x3C * 8)
|
|
#define CTRL_MAGIC (MARK + 0x1C * 8)
|
|
#define MAGIC_VALUE 0x42414450
|
|
|
|
extern void fill_run_();
|
|
extern void fill_init_();
|
|
extern void vid_dint_();
|
|
|
|
unsigned int fill_daddr;
|
|
unsigned int fill_dydx;
|
|
unsigned int fill_color;
|
|
|
|
void fill_rect(x, y, w, h, color)
|
|
int x;
|
|
int y;
|
|
int w;
|
|
int h;
|
|
int color;
|
|
{
|
|
if (w <= 0 || h <= 0) {
|
|
return;
|
|
}
|
|
fill_daddr = VRAM_BASE + (unsigned int)y * ROW_BITS + (unsigned int)x;
|
|
fill_dydx = ((unsigned int)h << 16) | (unsigned int)w;
|
|
fill_color = color ? 0x0000 : 0xFFFF;
|
|
fill_run_();
|
|
}
|
|
|
|
static void paint(x, y, w, h, color, ctx)
|
|
int x;
|
|
int y;
|
|
int w;
|
|
int h;
|
|
int color;
|
|
void *ctx;
|
|
{
|
|
fill_rect(x, y, w, h, color);
|
|
}
|
|
|
|
static void show_fault(code)
|
|
unsigned int code;
|
|
{
|
|
fill_init_();
|
|
fill_rect(0, 0, 1280, 64, 1);
|
|
*(unsigned int *)MARK = code;
|
|
for (;;) {
|
|
}
|
|
}
|
|
|
|
static unsigned char rxbuf[1600];
|
|
static unsigned char sa[16];
|
|
static unsigned char from[16];
|
|
static int fromlen;
|
|
static unsigned int rx_error;
|
|
|
|
/* Receive movie.bin over the OS UDP stack into a malloc'd bit buffer.
|
|
* Packet: u32 offset, u16 length, u16 seq, u16 crc16, then bytes.
|
|
* A final offset==expected/length==4 packet carries the 32-bit file checksum. */
|
|
static unsigned int receive_movie(expected)
|
|
unsigned int expected;
|
|
{
|
|
unsigned int ptr;
|
|
unsigned int offset;
|
|
unsigned int length;
|
|
unsigned int sent_sum;
|
|
unsigned int i;
|
|
unsigned char *dst;
|
|
int fd;
|
|
int n;
|
|
|
|
ptr = malloc_(expected);
|
|
if (ptr == 0) {
|
|
rx_error = 3;
|
|
return 0;
|
|
}
|
|
fd = socket_(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
if (fd < 0) {
|
|
rx_error = 4;
|
|
return 0;
|
|
}
|
|
sa_any(sa, NET_PORT);
|
|
if (bind_(fd, sa, SOCKADDR_LEN) < 0) {
|
|
close_(fd);
|
|
rx_error = 5;
|
|
return 0;
|
|
}
|
|
sent_sum = 0;
|
|
dst = (unsigned char *)ptr;
|
|
for (;;) {
|
|
fromlen = SOCKADDR_LEN;
|
|
n = recvfrom_(fd, rxbuf, (int)sizeof(rxbuf), 0, from, &fromlen);
|
|
if (n < 10) {
|
|
continue;
|
|
}
|
|
offset = (unsigned int)rxbuf[0]
|
|
| ((unsigned int)rxbuf[1] << 8)
|
|
| ((unsigned int)rxbuf[2] << 16)
|
|
| ((unsigned int)rxbuf[3] << 24);
|
|
length = (unsigned int)rxbuf[4] | ((unsigned int)rxbuf[5] << 8);
|
|
if (offset == expected && length == 4 && n >= 14) {
|
|
sent_sum = (unsigned int)rxbuf[10]
|
|
| ((unsigned int)rxbuf[11] << 8)
|
|
| ((unsigned int)rxbuf[12] << 16)
|
|
| ((unsigned int)rxbuf[13] << 24);
|
|
if (movie_checksum(dst, expected) == sent_sum) {
|
|
break;
|
|
}
|
|
sent_sum = 0;
|
|
continue;
|
|
}
|
|
if (length > (unsigned int)(n - 10)) {
|
|
continue;
|
|
}
|
|
if (offset > expected || length > expected - offset) {
|
|
continue;
|
|
}
|
|
for (i = 0; i < length; i++) {
|
|
dst[offset + i] = rxbuf[10 + i];
|
|
}
|
|
}
|
|
close_(fd);
|
|
if (sent_sum == 0) {
|
|
rx_error = 6;
|
|
return 0;
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
/* Poll the display interrupt pending bit. Interrupts are disabled; this is
|
|
* a status bit, not an ISR. A missing DPYINT only costs a bounded spin. */
|
|
static void wait_vsync()
|
|
{
|
|
unsigned int i;
|
|
unsigned short pending;
|
|
|
|
*(unsigned short *)0xC0000120 = 0;
|
|
for (i = 0; i < 200000; i++) {
|
|
pending = *(unsigned short *)0xC0000120;
|
|
if (pending & 0x0400) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
int main()
|
|
{
|
|
struct movie_header header;
|
|
unsigned int magic;
|
|
unsigned int frame;
|
|
unsigned int last;
|
|
unsigned int start;
|
|
unsigned int count;
|
|
unsigned int pace;
|
|
unsigned int net;
|
|
unsigned int wait;
|
|
unsigned int movie_base;
|
|
unsigned int movie_len;
|
|
unsigned int ticks;
|
|
unsigned int now;
|
|
unsigned int next;
|
|
int rc;
|
|
|
|
magic = *(unsigned int *)CTRL_MAGIC;
|
|
if (magic == MAGIC_VALUE) {
|
|
start = *(unsigned int *)CTRL_START;
|
|
count = *(unsigned int *)CTRL_COUNT;
|
|
pace = *(unsigned int *)CTRL_PACE;
|
|
net = *(unsigned int *)CTRL_NET;
|
|
wait = *(unsigned int *)CTRL_WAIT;
|
|
movie_base = *(unsigned int *)CTRL_MOVIE;
|
|
movie_len = *(unsigned int *)CTRL_MOVIELEN;
|
|
} else {
|
|
start = 0;
|
|
count = 0;
|
|
pace = 1;
|
|
net = NET_DEFAULT;
|
|
wait = 0;
|
|
movie_base = MOVIE_BASE;
|
|
movie_len = MOVIE_MAX;
|
|
}
|
|
if (net == 0 && NET_DEFAULT) {
|
|
net = 1;
|
|
}
|
|
|
|
if (net != 0) {
|
|
movie_len = NET_LEN;
|
|
*(unsigned int *)(MARK + 0x10 * 8) = 0x20;
|
|
movie_base = receive_movie(movie_len);
|
|
if (movie_base == 0) {
|
|
show_fault(0xBAD00000 | rx_error);
|
|
}
|
|
vid_dint_();
|
|
} else {
|
|
vid_dint_();
|
|
if (wait != 0) {
|
|
*(unsigned int *)(MARK + 0x10 * 8) = 0x10;
|
|
while (*(unsigned int *)CTRL_READY == 0) {
|
|
}
|
|
}
|
|
}
|
|
|
|
fill_init_();
|
|
*(unsigned short *)0xC00000A0 = 1;
|
|
fill_rect(0, 0, 1280, 1024, 0);
|
|
|
|
rc = movie_open((unsigned char *)movie_base, movie_len, &header);
|
|
if (rc != 0) {
|
|
show_fault(0xBAD00001);
|
|
}
|
|
|
|
last = header.frame_count;
|
|
if (last != 0) {
|
|
last = last - 1;
|
|
}
|
|
if (count != 0 && start + count - 1 < last) {
|
|
last = start + count - 1;
|
|
}
|
|
|
|
now = 0;
|
|
next = 0;
|
|
frame = 0;
|
|
while (frame <= last) {
|
|
if (pace != 0 && frame >= start) {
|
|
wait_vsync();
|
|
now += 5; /* 60/72 in 1/360 s units */
|
|
if (now < next) {
|
|
continue;
|
|
}
|
|
}
|
|
rc = movie_decode_frame((unsigned char *)movie_base, movie_len, frame,
|
|
&header, paint, 0);
|
|
if (rc != 0) {
|
|
show_fault(0xBAD00002);
|
|
}
|
|
ticks = movie_frame_ticks((unsigned char *)movie_base, movie_len,
|
|
frame, &header);
|
|
if (ticks < 1) {
|
|
ticks = 1;
|
|
}
|
|
next += 6 * ticks;
|
|
if (next + 360 < now) {
|
|
next = now;
|
|
}
|
|
*(unsigned int *)MARK = frame;
|
|
frame++;
|
|
}
|
|
|
|
*(unsigned int *)(MARK + 0x10 * 8) = (count != 0) ? 2 : 1;
|
|
for (;;) {
|
|
}
|
|
}
|