Un-ignored: the dev drive is the ground truth the restoration and emulator work constantly reference (DPL3/LIBDPL + VRENDER i860 renderer source, BT/RP live+dev game trees, VGL_LABS pod boot, scene/audio content). Kept in-repo for the pod-owner community. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1464 lines
30 KiB
C++
1464 lines
30 KiB
C++
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <dpltypes.h>
|
|
#include <dpl.h>
|
|
#include <dpl_host.h>
|
|
#include <vr_comms.h>
|
|
#include <linkio.h>
|
|
|
|
/*{{{ banner*/
|
|
/* **************************************************
|
|
|
|
Copyright DIVISION Limited (c) 1994
|
|
All rights reserved
|
|
|
|
|
|
File : vr_comms.c
|
|
Project : dpl interface
|
|
communication to 'velocirender for pxpl5'
|
|
|
|
Author : PJA
|
|
Date : 22/06/94
|
|
|
|
Function: communication to 'velocirender for pxpl5'
|
|
implements low-level messaging protocol
|
|
iserver transactions
|
|
byte-sex conversion for big-endian architectures
|
|
bootstrapping of vrender firmare onto vraster
|
|
|
|
History : Rev 1.0, 23 / 06 / 1994
|
|
|
|
**************************** */
|
|
/*}}} */
|
|
/*{{{ new VelociRender protocol*/
|
|
/* *****************************
|
|
|
|
new protocol is much simplified over original dNet;
|
|
basic protocol is l::bytes, with conditional behaviour on l
|
|
|
|
if (l & 0x80000000) then message is an iserver message,
|
|
otherwise a vr_net message
|
|
|
|
if message is to host, ((l >> 16) & 0xff) is id of sender,
|
|
if message is from host ((l >> 16) & 0xff) is id of receiver (target)
|
|
an outgoing id of 0xff implies a broadcast message
|
|
|
|
in all cases, (l & 0x3ff) is true number of bytes sent, 0..1023
|
|
|
|
Note that the i860s are now no longer in a position to communicate -
|
|
they simply input messages from the visual server, act on the messages
|
|
and sometimes reply.
|
|
|
|
*/
|
|
/*}}} */
|
|
|
|
#define verbose 0
|
|
/*
|
|
#define verbose 1
|
|
*/
|
|
|
|
int32 dpl_little_endian=1;
|
|
|
|
static char vr_msg_buffer[1040];
|
|
|
|
int32 dpl_frame_replied=1;
|
|
int32 vr_holding_bytes=0;
|
|
static char vr_holding_buffer[1040];
|
|
|
|
/*{{{ endian conversion / buffer access*/
|
|
/*{{{ static char *put_char ( char *b, char v )*/
|
|
static char *put_char ( char *b, char v )
|
|
{
|
|
*b++=v;
|
|
|
|
return b;
|
|
}
|
|
/*}}} */
|
|
/*{{{ static char *put_int8 ( char *b, int8 v )*/
|
|
static char *put_int8 ( char *b, int8 v )
|
|
{
|
|
char *cv=(char *) &v;
|
|
|
|
*b++=*cv;
|
|
|
|
return b;
|
|
}
|
|
/*}}} */
|
|
/*{{{ static char *put_int16 ( char *b, int16 v )*/
|
|
static char *put_int16 ( char *b, int16 v )
|
|
{
|
|
char *cv=(char *) &v;
|
|
|
|
if (dpl_little_endian) {
|
|
*b++=*cv++;
|
|
*b++=*cv++;
|
|
|
|
return b;
|
|
}
|
|
else {
|
|
b[0]=cv[1];
|
|
b[1]=cv[0];
|
|
|
|
return b+2;
|
|
}
|
|
}
|
|
/*}}} */
|
|
/*{{{ static char *put_int32 ( char *b, int32 v )*/
|
|
static char *put_int32 ( char *b, int32 v )
|
|
{
|
|
char *cv=(char *) &v;
|
|
|
|
if (dpl_little_endian) {
|
|
*b++=*cv++;
|
|
*b++=*cv++;
|
|
*b++=*cv++;
|
|
*b++=*cv++;
|
|
|
|
return b;
|
|
}
|
|
else {
|
|
b[0]=cv[3];
|
|
b[1]=cv[2];
|
|
b[2]=cv[1];
|
|
b[3]=cv[0];
|
|
|
|
return b+4;
|
|
}
|
|
}
|
|
/*}}} */
|
|
/*{{{ static char *put_fast_int32 ( char *b, int32 v )*/
|
|
static char *put_fast_int32 ( char *b, int32 v )
|
|
{
|
|
char *cv=(char *) &v;
|
|
|
|
if (dpl_little_endian) {
|
|
*(int *) b=v;
|
|
|
|
return b+4;
|
|
}
|
|
else {
|
|
b[0]=cv[3];
|
|
b[1]=cv[2];
|
|
b[2]=cv[1];
|
|
b[3]=cv[0];
|
|
|
|
return b+4;
|
|
}
|
|
}
|
|
/*}}} */
|
|
/*{{{ static char *put_float32 ( char *b, float32 v )*/
|
|
static char *put_float32 ( char *b, float32 v )
|
|
{
|
|
char *cv=(char *) &v;
|
|
|
|
if (dpl_little_endian) {
|
|
*b++=*cv++;
|
|
*b++=*cv++;
|
|
*b++=*cv++;
|
|
*b++=*cv++;
|
|
|
|
return b;
|
|
}
|
|
else {
|
|
|
|
b[0]=cv[3];
|
|
b[1]=cv[2];
|
|
b[2]=cv[1];
|
|
b[3]=cv[0];
|
|
|
|
return b+4;
|
|
}
|
|
}
|
|
/*}}} */
|
|
/*{{{ static char *put_struct8 ( char *b, void *v, int n_bytes )*/
|
|
static char *put_struct8 ( char *b, void *v, int n_bytes )
|
|
{
|
|
memcpy ( b, v, n_bytes );
|
|
|
|
return b+n_bytes;
|
|
}
|
|
/*}}} */
|
|
/*{{{ static char *put_struct32 ( char *b, void *v, int n_bytes )*/
|
|
static char *put_struct32 ( char *b, void *v, int n_bytes )
|
|
{
|
|
if (dpl_little_endian) {
|
|
memcpy ( b, v, n_bytes );
|
|
|
|
return b+n_bytes;
|
|
}
|
|
else {
|
|
int i;
|
|
char *cv=(char *) v;
|
|
|
|
for (i=0; i<n_bytes>>2; i++ ) {
|
|
|
|
b[0]=cv[3];
|
|
b[1]=cv[2];
|
|
b[2]=cv[1];
|
|
b[3]=cv[0];
|
|
|
|
b +=4;
|
|
cv+=4;
|
|
}
|
|
return b;
|
|
}
|
|
}
|
|
/*}}} */
|
|
/*{{{ static char *put_string ( char *b, char *s )*/
|
|
static char *put_string ( char *b, char *s )
|
|
{
|
|
int n_bytes=strlen(s)+1;
|
|
|
|
memcpy ( b, s, n_bytes );
|
|
|
|
return b+n_bytes;
|
|
}
|
|
/*}}} */
|
|
|
|
/*{{{ static char *get_char ( char *b, char *v )*/
|
|
static char *get_char ( char *b, char *v )
|
|
{
|
|
*v=*b++;
|
|
return b;
|
|
}
|
|
/*}}} */
|
|
/*{{{ static char *get_int8 ( char *b, int8 *v )*/
|
|
static char *get_int8 ( char *b, int8 *v )
|
|
{
|
|
char *cv=(char *) &v;
|
|
|
|
*cv++=*b++;
|
|
|
|
return b;
|
|
}
|
|
/*}}} */
|
|
/*{{{ static char *get_int16 ( char *b, int16 *v )*/
|
|
static char *get_int16 ( char *b, int16 *v )
|
|
{
|
|
char *cv=(char *) v;
|
|
|
|
if (dpl_little_endian) {
|
|
*cv++=*b++;
|
|
*cv++=*b++;
|
|
|
|
return b;
|
|
}
|
|
else {
|
|
cv[0]=b[1];
|
|
cv[1]=b[0];
|
|
|
|
return b+2;
|
|
}
|
|
}
|
|
/*}}} */
|
|
/*{{{ static char *get_int32 ( char *b, int32 *v )*/
|
|
static char *get_int32 ( char *b, int32 *v )
|
|
{
|
|
char *cv=(char *) v;
|
|
|
|
if (dpl_little_endian) {
|
|
*cv++ = *b++;
|
|
*cv++ = *b++;
|
|
*cv++ = *b++;
|
|
*cv++ = *b++;
|
|
|
|
return b;
|
|
}
|
|
else {
|
|
|
|
cv[3]=b[0];
|
|
cv[2]=b[1];
|
|
cv[1]=b[2];
|
|
cv[0]=b[3];
|
|
|
|
return b+4;
|
|
}
|
|
}
|
|
/*}}} */
|
|
/*{{{ static char *get_float32 ( char *b, float32 *v )*/
|
|
static char *get_float32 ( char *b, float32 *v )
|
|
{
|
|
char *cv=(char *) v;
|
|
|
|
if (dpl_little_endian) {
|
|
*cv++ = *b++;
|
|
*cv++ = *b++;
|
|
*cv++ = *b++;
|
|
*cv++ = *b++;
|
|
|
|
return b;
|
|
}
|
|
else {
|
|
|
|
cv[3]=b[0];
|
|
cv[2]=b[1];
|
|
cv[1]=b[2];
|
|
cv[0]=b[3];
|
|
|
|
return b+4;
|
|
}
|
|
}
|
|
/*}}} */
|
|
/*{{{ static char *get_struct8 ( char *b, void *v, int n_bytes )*/
|
|
static char *get_struct8 ( char *b, void *v, int n_bytes )
|
|
{
|
|
memcpy ( v, b, n_bytes );
|
|
|
|
return b+n_bytes;
|
|
}
|
|
/*}}} */
|
|
/*{{{ static char *get_struct32 ( char *b, void *v, int n_bytes )*/
|
|
static char *get_struct32 ( char *b, void *v, int n_bytes )
|
|
{
|
|
if (dpl_little_endian) {
|
|
memcpy ( v, b, n_bytes );
|
|
|
|
return b+n_bytes;
|
|
}
|
|
else {
|
|
int i;
|
|
char *cv=(char *) v;
|
|
|
|
for (i=0; i<n_bytes>>2; i++ ) {
|
|
|
|
cv[0]=b[3];
|
|
cv[1]=b[2];
|
|
cv[2]=b[1];
|
|
cv[3]=b[0];
|
|
|
|
b +=4;
|
|
cv+=4;
|
|
}
|
|
return b;
|
|
}
|
|
}
|
|
/*}}} */
|
|
/*{{{ static char *get_string ( char *b, char *s )*/
|
|
static char *get_string ( char *b, char *s )
|
|
{
|
|
int n_bytes=strlen(b)+1;
|
|
|
|
memcpy ( s, b, n_bytes );
|
|
|
|
return b+n_bytes;
|
|
}
|
|
/*}}} */
|
|
|
|
#define put_byte(a,b) put_int8(a,b)
|
|
#define get_byte(a,b) get_int8(a,b)
|
|
/*}}} */
|
|
|
|
/*{{{ low-level protocol transmit / receive*/
|
|
#define send_protocol send_link_protocol
|
|
|
|
static int32 use_fifo=0;
|
|
|
|
static int32
|
|
send_link_protocol ( int target, void *data, int n_bytes, int iserver, int iserver_enable );
|
|
|
|
/* #define outRecord(a,b) outveryfast((a),C012,(b)) */
|
|
|
|
static int32 isaction=0;
|
|
static int32 isactions=0;
|
|
|
|
#if 0
|
|
/*{{{ multi-pipe message formatting*/
|
|
typedef struct remote_msg {
|
|
char remote_printf[256];
|
|
char *printf_cp;
|
|
int32 printf_chars;
|
|
} remote_msg;
|
|
|
|
static remote_msg remote_messages[4];
|
|
static int32 remote_init=0;
|
|
|
|
/*{{{ static void flush_remote_messages ()*/
|
|
static void flush_remote_messages ()
|
|
{
|
|
int i;
|
|
for (i=0; i<4; i++) {
|
|
remote_msg *rp=&remote_messages[i];
|
|
|
|
if (rp->printf_chars) {
|
|
printf (rp->remote_printf);
|
|
rp->printf_cp=rp->remote_printf;
|
|
rp->printf_chars=0;
|
|
}
|
|
}
|
|
}
|
|
/*}}} */
|
|
/*{{{ static void vr_printf ( char * b)*/
|
|
static void vr_printf ( int32 him, char * b)
|
|
{
|
|
remote_msg *rp;
|
|
char c, *cp, *cp0;
|
|
int chars;
|
|
|
|
/*{{{ do init*/
|
|
if (remote_init==0) {
|
|
int i;
|
|
for (i=0; i<4; i++) {
|
|
rp=&remote_messages[i];
|
|
rp->printf_chars=0;
|
|
rp->printf_cp=rp->remote_printf;
|
|
}
|
|
remote_init=1;
|
|
}
|
|
/*}}} */
|
|
|
|
rp=&remote_messages[him-2];
|
|
|
|
cp =rp->printf_cp;
|
|
cp0=rp->remote_printf;
|
|
chars=rp->printf_chars;
|
|
|
|
while (c=*b++) {
|
|
if (c!=0xa) {
|
|
if (c==0xd) c='\n';
|
|
*cp++=c;
|
|
chars++;
|
|
}
|
|
|
|
if ((c=='\n') || (chars > 253)) {
|
|
*cp++=0x0;
|
|
printf (cp0);
|
|
fflush(stdout);
|
|
cp=cp0;
|
|
sprintf ( cp, "%d)", him );
|
|
while (*cp++)
|
|
;
|
|
chars=4;
|
|
}
|
|
}
|
|
|
|
rp->printf_cp=cp;
|
|
rp->printf_chars=chars;
|
|
}
|
|
|
|
/*}}} */
|
|
/*}}} */
|
|
#endif
|
|
/*{{{ iserver_action ( int32 him, char *boot_packet );*/
|
|
|
|
static
|
|
int32 iserver_action ( int him, char *boot_packet )
|
|
{
|
|
char *cp, *b=boot_packet, *mesg="VelociRender";
|
|
int16 l=0;
|
|
|
|
isactions++;
|
|
isaction = (int32) (*b);
|
|
|
|
switch (isaction) {
|
|
/*{{{ case 40 : commandline*/
|
|
case 40 :
|
|
#if (verbose)
|
|
printf("{%d} Iserver_action returning command line \"%s\".\n",him, mesg);
|
|
#endif
|
|
l=strlen(mesg);
|
|
|
|
b=put_char ( b, 0x0 );
|
|
b=put_int16 ( b, l );
|
|
b=put_struct8 ( b, mesg, l );
|
|
|
|
send_protocol ( him, boot_packet, l+3, 1, 0 );
|
|
|
|
break;
|
|
/*}}} */
|
|
/*{{{ case 42 : version*/
|
|
case 42 :
|
|
#if (verbose)
|
|
printf("{%d} Iserver_action returning iserver version 1.50\n", him );
|
|
#endif
|
|
|
|
|
|
b=put_char (b, 0 ); /* result */
|
|
b=put_char (b, 15 ); /* current iserver 1.50 */
|
|
b=put_char (b, 1 );
|
|
b=put_char (b, 1 );
|
|
b=put_char (b, 1 );
|
|
|
|
send_protocol ( him, boot_packet, 5, 1, 0 );
|
|
|
|
break;
|
|
/*}}} */
|
|
/*{{{ case 32 : getenv*/
|
|
case 32 :
|
|
#if (verbose)
|
|
printf("{%d} Iserver_action doing getenv..\n", him);
|
|
#endif
|
|
|
|
b++;
|
|
b = get_int16 ( b, &l );
|
|
|
|
#if (verbose)
|
|
printf("{%d} l=%d\n", him, l );
|
|
#endif
|
|
|
|
b[l]='\0';
|
|
|
|
#if (verbose)
|
|
printf("{%d} getenv of %s\n", him, b );
|
|
#endif
|
|
|
|
cp = getenv(b);
|
|
|
|
#if (verbose)
|
|
printf("{%d} which is %s\n", him, cp );
|
|
#endif
|
|
|
|
l = strlen(cp);
|
|
b = boot_packet;
|
|
|
|
b = put_byte ( b, 0 );
|
|
b = put_int16 ( b, l );
|
|
b = put_struct8 ( b, cp, l );
|
|
|
|
send_protocol ( him, boot_packet, l+3, 1, 0 );
|
|
|
|
break;
|
|
/*}}} */
|
|
/*{{{ case 24 : fputblock*/
|
|
case 24 :
|
|
{
|
|
int32 streamID;
|
|
|
|
b++;
|
|
|
|
b=get_int32 ( b, &streamID );
|
|
b=get_int16 ( b, &l );
|
|
|
|
b[l]= '\0';
|
|
|
|
if ((streamID == 1) || (streamID == 2)) {
|
|
printf ("%d):%s", him, b );
|
|
|
|
b=boot_packet;
|
|
b=put_byte ( b, 0 );
|
|
b=put_int16 ( b, l );
|
|
|
|
send_protocol ( him, boot_packet, 3, 1, 0 );
|
|
}
|
|
else {
|
|
printf ("i860 error : attempt to fputblock to NOT stdout\n" );
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
break;
|
|
/*}}} */
|
|
/*{{{ case 13 : fwrite*/
|
|
case 13 :
|
|
{
|
|
int32 streamID;
|
|
char c;
|
|
|
|
b++;
|
|
|
|
b=get_int32 ( b, &streamID );
|
|
b=get_int16 ( b, &l );
|
|
|
|
b[l]= '\0';
|
|
|
|
if ((streamID == 1) || (streamID == 2)) {
|
|
printf ("%d):%s", him, b );
|
|
|
|
b=boot_packet;
|
|
|
|
b=put_byte ( b, 0 );
|
|
b=put_int16 ( b, l );
|
|
|
|
send_protocol ( him, boot_packet, 3, 1, 0 );
|
|
}
|
|
else {
|
|
printf ( "ERROR : i860 attempting to fwrite\n" );
|
|
return 0;
|
|
}
|
|
}
|
|
break;
|
|
/*}}} */
|
|
/*{{{ case 16 : fflush - don't do owt*/
|
|
case 16 :
|
|
#if (verbose)
|
|
printf("{%d} Iserver_action ignoring fflush.\n", him);
|
|
#endif
|
|
|
|
b=put_byte ( b, 0 );
|
|
b=put_byte ( b, 1 );
|
|
b=put_byte ( b, 0 );
|
|
|
|
send_protocol ( him, boot_packet, 3, 1, 0 );
|
|
|
|
break;
|
|
/*}}} */
|
|
default :
|
|
printf ("iserver_transaction, unexpected tag (%d) in %s\n",
|
|
isaction, __lastop);
|
|
exit(666);
|
|
return 0;
|
|
break;
|
|
}
|
|
return 1;
|
|
}
|
|
/*}}} */
|
|
/*{{{ receive_protocol ( int *sender, void *data, int *n_bytes, int *iserver )*/
|
|
static int32
|
|
cntl_word=0;
|
|
|
|
static int32
|
|
receive_protocol ( int *sender, void *data, int *n_bytes, int *iserver )
|
|
{
|
|
int32 nb=0, length_word, i;
|
|
char *b=(char *) &nb;
|
|
|
|
if (inRecord ( b, 4 )) {
|
|
get_int32 ( b, &length_word );
|
|
cntl_word=length_word;
|
|
|
|
*sender=(length_word >> 16) & 0xff;
|
|
|
|
if (length_word & 0x80000000)
|
|
*iserver=1;
|
|
else
|
|
*iserver=0;
|
|
|
|
nb=length_word&0xffff;
|
|
|
|
if (nb > 1040) {
|
|
printf ("protocol error, length %d too big\n", nb );
|
|
return 0;
|
|
}
|
|
|
|
if (inRecord ( data, nb )) {
|
|
char *cd=(char *) data;
|
|
|
|
*n_bytes=nb;
|
|
|
|
return 1;
|
|
}
|
|
else {
|
|
printf ("protocol error, %d bytes not completed (is=%d)\n",
|
|
nb, *iserver );
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
else {
|
|
printf ("protocol error, length word not received\n" );
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
/*}}} */
|
|
/*{{{ static void handle_iserver_stuff()*/
|
|
static void handle_iserver_stuff ( void )
|
|
{
|
|
char *b;
|
|
|
|
while (vr_holding_bytes == 0) {
|
|
int32 iserver;
|
|
int32 sender;
|
|
b=&vr_holding_buffer[0];
|
|
|
|
if (altRecord() == 0)
|
|
return;
|
|
else {
|
|
if ((receive_protocol ( &sender, b, &vr_holding_bytes, &iserver )) == 0) {
|
|
linkio_error ("ERROR : receive protocol fail during iserver handling\n" );
|
|
return;
|
|
}
|
|
if (iserver) {
|
|
if (iserver_action ( sender, b ) == 0) {
|
|
linkio_error ("ERROR : iserver transaction failure during transmit\n" );
|
|
return;
|
|
}
|
|
else {
|
|
vr_holding_bytes=0;
|
|
}
|
|
}
|
|
else {
|
|
printf ("handle_iserver_stuff found REAL DATA packet\n" );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*}}} */
|
|
/*{{{ send_FIFO_protocol ( int target, void *data, int n_bytes, int iserver, int iserver_enable )*/
|
|
extern int outsw ( int32 length_word, int32 port, void *address, int32 bytes );
|
|
extern int32 C012;
|
|
|
|
int32
|
|
send_FIFO_protocol ( int target, void *data, int n_bytes, int iserver, int iserver_enable )
|
|
{
|
|
/* try to figure out a scam for less copies when endian_fix is deasserted */
|
|
static int32 good_sends=0;
|
|
int32 t=0;
|
|
char length_word[4];
|
|
|
|
char *cdata=(char *) data;
|
|
|
|
if ((iserver == 0) & iserver_enable)
|
|
handle_iserver_stuff();
|
|
|
|
if (n_bytes > 1024) {
|
|
printf ("Attempt to send %d bytes in packet, dying!!\n", n_bytes );
|
|
exit(666);
|
|
}
|
|
if (iserver) {
|
|
if (n_bytes & 1)
|
|
n_bytes++;
|
|
put_int32 ( length_word, n_bytes | (target << 16) | 0x80000000 );
|
|
}
|
|
else
|
|
put_int32 ( length_word, (0xff << 16) | n_bytes ); /* top bit clear = broadcast */
|
|
|
|
return outsw ( *((int32 *) (&length_word[0])), C012, data, n_bytes );
|
|
}
|
|
/*}}} */
|
|
/*{{{ send_link_protocol ( int target, void *data, int n_bytes, int iserver, int iserver_enable )*/
|
|
static int32
|
|
send_link_protocol ( int target, void *data, int n_bytes, int iserver, int iserver_enable )
|
|
{
|
|
/* try to figure out a scam for less copies when endian_fix is deasserted */
|
|
static int32 good_sends=0;
|
|
char length_word[4];
|
|
char *cdata=(char *) data;
|
|
|
|
if (use_fifo)
|
|
return send_FIFO_protocol ( target, data, n_bytes, iserver, iserver_enable );
|
|
|
|
if ((iserver == 0) & iserver_enable)
|
|
handle_iserver_stuff();
|
|
|
|
if (n_bytes > 1024) {
|
|
printf ("Attempt to send %d bytes in packet, dying!!\n", n_bytes );
|
|
exit(666);
|
|
}
|
|
if (iserver) {
|
|
if (n_bytes & 1)
|
|
n_bytes++;
|
|
put_int32 ( length_word, n_bytes | (target << 16) | 0x80000000 );
|
|
}
|
|
else
|
|
put_int32 ( length_word, (0xff << 16) | n_bytes ); /* top bit clear = broadcast */
|
|
|
|
if (outRecord ( length_word, 4 ) == 0) {
|
|
#if (verbose)
|
|
printf("send_protocol failed to squirt length word, good_sends=%d\n",
|
|
good_sends );
|
|
exit(666);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (outRecord ( data, n_bytes ) == 0) {
|
|
#if (verbose)
|
|
printf("send_protocol failed to squirt data, good_sends=%d\n",
|
|
good_sends );
|
|
exit(666);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
if (iserver == 0) good_sends++;
|
|
return 1;
|
|
}
|
|
/*}}} */
|
|
|
|
|
|
/*}}} */
|
|
|
|
/*{{{ velocirender_receive ( vr_action *action, void *node, int32 *n_bytes )*/
|
|
int32
|
|
velocirender_receive ( vr_action *action, void *node, int32 *n_bytes )
|
|
{
|
|
char *b=&vr_msg_buffer[0];
|
|
int32 iserver=1;
|
|
int32 nb, sender, received=0;
|
|
|
|
#if (verbose)
|
|
printf ("call to velocirender_receive\n" );
|
|
#endif
|
|
|
|
if (vr_holding_bytes) {
|
|
nb=vr_holding_bytes & 0xff;
|
|
|
|
b=get_int32 ( b, (int32 *) action );
|
|
b=get_struct32 ( b, node, nb - 4 );
|
|
|
|
*n_bytes=nb-4;
|
|
|
|
vr_holding_bytes = 0;
|
|
|
|
if ((*action) == vr_draw_scene_action) {
|
|
printf ("draw scene ack found in receive\n" );
|
|
dpl_frame_replied=1;
|
|
}
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
do {
|
|
do {
|
|
if ((receive_protocol ( &sender, b, &nb, &iserver )) == 0)
|
|
return 0;
|
|
if (iserver) {
|
|
if (iserver_action ( sender, b ) == 0)
|
|
return 0;
|
|
}
|
|
} while (iserver);
|
|
|
|
if (nb < 8) {
|
|
printf ("Huh, at least 8 bytes expected - cntl word=0x%x\n",
|
|
cntl_word );
|
|
return 0;
|
|
}
|
|
b=get_int32 ( b, (int32 *) action );
|
|
b=get_struct32 ( b, node, nb - 4 );
|
|
|
|
*n_bytes=nb-4;
|
|
|
|
if ((*action) == vr_draw_scene_action) {
|
|
printf ("draw scene ack found in receive\n" );
|
|
dpl_frame_replied=1;
|
|
}
|
|
else
|
|
received = 1;
|
|
|
|
} while (received == 0);
|
|
|
|
return 1;
|
|
}
|
|
/*}}} */
|
|
/*{{{ velocirender_frameack ( vr_action *action, void *node, int32 *n_bytes )*/
|
|
int32
|
|
velocirender_frameack ( void )
|
|
{
|
|
vr_action action;
|
|
int32 n_bytes;
|
|
char *b=&vr_msg_buffer[0];
|
|
int32 iserver=1;
|
|
int32 sender, received=0;
|
|
|
|
#if (verbose)
|
|
printf ("call to velocirender_receive\n" );
|
|
#endif
|
|
|
|
if (vr_holding_bytes) {
|
|
n_bytes=vr_holding_bytes & 0xff;
|
|
|
|
vr_holding_bytes = 0;
|
|
|
|
b=get_int32 ( b, (int32 *) &action );
|
|
if (action == vr_draw_scene_action) {
|
|
dpl_frame_replied=1;
|
|
return 1;
|
|
}
|
|
else {
|
|
printf ("Unexpected vr_net input 0x%x during frame ack\n", action );
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
do {
|
|
if ((receive_protocol ( &sender, b, &n_bytes, &iserver )) == 0)
|
|
return 0;
|
|
if (iserver) {
|
|
if (iserver_action ( sender, b ) == 0)
|
|
return 0;
|
|
}
|
|
} while (iserver);
|
|
|
|
if ((n_bytes) < 8) {
|
|
printf ("Huh, at least 8 bytes expected - cntl word=0x%x\n",
|
|
cntl_word );
|
|
return 0;
|
|
}
|
|
b=get_int32 ( b, (int32 *) &action );
|
|
if (action == vr_draw_scene_action) {
|
|
dpl_frame_replied=1;
|
|
return 1;
|
|
}
|
|
else {
|
|
printf ("Unexpected vr_net input 0x%x during frame ack\n", action );
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
/*}}} */
|
|
/*{{{ velocirender_inputstatus ( void )*/
|
|
int32
|
|
velocirender_inputstatus ( void )
|
|
{
|
|
if (vr_holding_bytes)
|
|
return 1;
|
|
else if (altRecord())
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
/*}}} */
|
|
/*{{{ velocirender_transmit ( vr_action action, void *data, int32 n_bytes )*/
|
|
int32
|
|
velocirender_transmit ( vr_action action, void *data, int32 n_bytes,
|
|
int32 endian_fix )
|
|
{
|
|
char *b=&vr_msg_buffer[0];
|
|
|
|
/* this is a bit nasty to do non-endian fix stuff
|
|
without additional memcpy */
|
|
|
|
if (action == vr_draw_scene_action) {
|
|
if (dpl_frame_replied==0)
|
|
velocirender_frameack();
|
|
dpl_frame_replied=0;
|
|
}
|
|
|
|
if (dpl_little_endian || (endian_fix == 0)) {
|
|
int32 t1, t2;
|
|
char *at1=(char *) &t1;
|
|
char *at2=(char *) &t2;
|
|
|
|
handle_iserver_stuff();
|
|
n_bytes+=4;
|
|
|
|
put_fast_int32 ( at1, (0xff << 16) | n_bytes);
|
|
put_fast_int32 ( at2, (int32) action);
|
|
|
|
if (use_fifo) {
|
|
outsw ( 0, C012, at2, 4 );
|
|
return outsw ( t1, C012, data, n_bytes-4 );
|
|
}
|
|
else {
|
|
outRecord ( at1, 4 );
|
|
outRecord ( at2, 4 );
|
|
|
|
return outRecord ( data, n_bytes-4 );
|
|
}
|
|
}
|
|
else {
|
|
b=put_int32 ( b, (int32) action );
|
|
|
|
b=put_struct32 ( b, data, n_bytes );
|
|
send_protocol ( 0xff, vr_msg_buffer, n_bytes+4, 0, 1 );
|
|
}
|
|
return 1;
|
|
}
|
|
/*}}} */
|
|
/*{{{ velocirender_packetize ( vr_action action, void *data, int32 n_bytes, int32 endian_fix )*/
|
|
int32
|
|
velocirender_packetize ( vr_action action, void *data, int32 n_bytes, int32 endian_fix )
|
|
{
|
|
char *cdata=(char *) data;
|
|
int max_bytes=512-4;
|
|
|
|
while (n_bytes > max_bytes) {
|
|
if (velocirender_transmit ( action, cdata, max_bytes, endian_fix ) == 0)
|
|
return 0;
|
|
|
|
n_bytes-=max_bytes;
|
|
cdata +=max_bytes;
|
|
}
|
|
|
|
if (n_bytes) {
|
|
if (velocirender_transmit ( action, cdata, n_bytes, endian_fix ) == 0)
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
/*}}} */
|
|
|
|
/*{{{ code for booting transputers*/
|
|
|
|
#define boot_packet_size (2*1024)
|
|
|
|
static char *__boot_packet,
|
|
*__packet,
|
|
*__blk;
|
|
|
|
/*{{{ startup_transaction ( void )*/
|
|
static int32
|
|
startup_transaction ( void )
|
|
{
|
|
int32 t;
|
|
int32 iserver, sender, n_bytes;
|
|
vr_action action;
|
|
|
|
#if (verbose)
|
|
printf ("**** startup transaction\n" );
|
|
#endif
|
|
|
|
t = receive_protocol ( &sender, __boot_packet, &n_bytes, &iserver );
|
|
if (t == 0) return 0;
|
|
|
|
if (iserver) {
|
|
if (iserver_action ( sender, __boot_packet ) == 0)
|
|
return 0;
|
|
}
|
|
else {
|
|
printf ("ERROR : unexpected vrNet transaction in startup-handshake\n" );
|
|
return 0;
|
|
}
|
|
|
|
return n_bytes;
|
|
}
|
|
/*}}} */
|
|
/*{{{ startup_handshake*/
|
|
static int32
|
|
startup_handshake ()
|
|
{
|
|
int32 ret;
|
|
|
|
/*{{{ sorry...*/
|
|
/*
|
|
|
|
This is deeply Yuck, and relies on the knowledge that
|
|
the C run-time boots up and does 3 iserver transactions before
|
|
closing down
|
|
|
|
Phil
|
|
|
|
*/
|
|
/*}}} */
|
|
|
|
#if verbose
|
|
printf ("Startup handshake velocirender v 1.0\n");
|
|
#endif
|
|
|
|
/* 1 getenv*/
|
|
link_io_ABORTCHECK;
|
|
if ((ret=startup_transaction ()) == 0) return 0;
|
|
#if verbose
|
|
printf ("Startup handshake ret 1 was %d (%d)\n", ret, isaction );
|
|
#endif
|
|
|
|
|
|
/* 2 getenv*/
|
|
link_io_ABORTCHECK;
|
|
if ((ret=startup_transaction ()) == 0) return 0;
|
|
#if verbose
|
|
printf ("Startup handshake ret 2 was %d (%d)\n", ret, isaction );
|
|
#endif
|
|
|
|
/* 3 getenv*/
|
|
link_io_ABORTCHECK;
|
|
if ((ret=startup_transaction ()) == 0) return 0;
|
|
#if verbose
|
|
printf ("Startup handshake ret 3 was %d (%d)\n", ret, isaction );
|
|
#endif
|
|
|
|
return 1;
|
|
|
|
link_io_EXITZERO;
|
|
}
|
|
/*}}} */
|
|
|
|
/*{{{ boot_xputer*/
|
|
int32 boot_xputer ( char *f, int32 n_860s )
|
|
{
|
|
|
|
FILE *fp;
|
|
int32 n_read;
|
|
int32 total=0,
|
|
ok_to_fifo;
|
|
|
|
reset();
|
|
#if verbose
|
|
printf ("boot_xputer with %s\n", f );
|
|
#endif
|
|
if ((fp=fopen(f, "rb" )) == 0) {
|
|
printf ("Couldnt open %s\n", f );
|
|
return 0;
|
|
}
|
|
|
|
link_io_ABORTCHECK;
|
|
|
|
n_read=fread ( __boot_packet, 1, boot_packet_size, fp );
|
|
total=n_read;
|
|
|
|
ok_to_fifo=fifo_ok_status();
|
|
|
|
while (n_read == boot_packet_size) {
|
|
if (outRecord(__boot_packet, boot_packet_size )==0) {
|
|
#if verbose
|
|
printf ("Boot_packet returned 0\n");
|
|
#endif
|
|
fclose(fp);
|
|
return(0);
|
|
}
|
|
n_read=fread ( __boot_packet, 1, boot_packet_size, fp );
|
|
total+=n_read;
|
|
}
|
|
|
|
fclose (fp);
|
|
/*{{{ */
|
|
#if verbose
|
|
printf ("fclosed tranny boot file\n ");
|
|
#endif
|
|
/*}}} */
|
|
|
|
link_io_ABORTCHECK;
|
|
|
|
if (n_read != 0) {
|
|
if (outRecord(__boot_packet, n_read )==0) {
|
|
/*{{{ */
|
|
#if verbose
|
|
printf ("Boot_packet returned 0\n");
|
|
#endif
|
|
/*}}} */
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
if (ok_to_fifo) {
|
|
printf ("waiting to become NOT ok to fifo\n" );
|
|
while(ok_to_fifo) {
|
|
ok_to_fifo=fifo_ok_status();
|
|
}
|
|
}
|
|
|
|
printf ("waiting to become ok to fifo\n" );
|
|
|
|
while(ok_to_fifo == 0)
|
|
ok_to_fifo=fifo_ok_status();
|
|
|
|
printf ("now its ok to fifo\n" );
|
|
|
|
*/
|
|
|
|
{
|
|
int32 i;
|
|
|
|
/*{{{ */
|
|
#if verbose
|
|
printf ("about to startup_handshake for %d 860s\n", n_860s );
|
|
#endif
|
|
/*}}} */
|
|
for (i=0; i<n_860s; i++ ) {
|
|
startup_handshake ();
|
|
|
|
link_io_ABORTCHECK;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
|
|
link_io_EXITZERO;
|
|
}
|
|
/*}}} */
|
|
|
|
#define link_address(a) (int32) (0x80000000 | (a<<2))
|
|
/*{{{ void resetLoop()*/
|
|
static void resetLoop ( int n )
|
|
{
|
|
clock_t the_time=clock();
|
|
int i;
|
|
|
|
for (i=0; i<n; i++ ) {
|
|
while (the_time==clock())
|
|
;
|
|
the_time=clock();
|
|
}
|
|
}
|
|
/*}}} */
|
|
|
|
/*{{{ static boot_HSP()*/
|
|
static void boot_HSP ( char *f, int32 link_A, int32 link_B )
|
|
{
|
|
FILE *fp;
|
|
int32 total=0;
|
|
char *cp = (char *) __boot_packet, *lp, *rp;
|
|
|
|
int32 chars=0;
|
|
|
|
/* set up packet header - HSPcode, link, bytes*/
|
|
lp = cp; /* record link address slot */
|
|
cp = put_int32 ( cp, link_address(link_A));
|
|
cp = put_int32 ( cp, 128 );
|
|
rp=cp;
|
|
|
|
if (link_A==link_B) {
|
|
link_B=-1;
|
|
}
|
|
|
|
#if (verbose)
|
|
printf ("Boot hsp from %s links 0x%lx 0x%lx\n", f, link_A, link_B );
|
|
#endif
|
|
|
|
if ((fp=fopen(f, "rb" ))!=0) {
|
|
/* boot file fp*/
|
|
chars = fread (rp, 1, 128, fp );
|
|
|
|
while (chars == 128 ) {
|
|
/* send packets of 128 */
|
|
total+=128;
|
|
cp=lp;
|
|
|
|
cp = put_int32 ( cp, link_address(link_A));
|
|
|
|
velocirender_transmit ( vr_hspcode_action, lp, 128+8, 0 );
|
|
|
|
if (link_B >= 0) {
|
|
cp=lp;
|
|
cp = put_int32 ( cp, link_address(link_B));
|
|
|
|
velocirender_transmit ( vr_hspcode_action, lp, 128+8, 0 );
|
|
}
|
|
chars = fread (rp, 1, 128, fp );
|
|
}
|
|
if (chars != 0) {
|
|
/* send last few*/
|
|
total+=chars;
|
|
cp = lp;
|
|
cp = put_int32 ( cp, link_address(link_A));
|
|
cp = put_int32 ( cp, chars );
|
|
|
|
velocirender_transmit ( vr_hspcode_action, lp, chars+8, 0 );
|
|
|
|
if (link_B >= 0) {
|
|
cp = lp;
|
|
cp = put_int32 ( cp, link_address(link_B));
|
|
|
|
velocirender_transmit ( vr_hspcode_action, lp, chars+8, 0 );
|
|
}
|
|
}
|
|
fclose (fp);
|
|
|
|
#if (verbose)
|
|
printf ("Booted %ld bytes to HSP\n", total );
|
|
#endif
|
|
}
|
|
else {
|
|
printf ("Couldnt open HSP file \"%s\".\n", f );
|
|
}
|
|
}
|
|
|
|
|
|
/*}}} */
|
|
/*{{{ static i860_args()*/
|
|
static void i860_args ( char *argv )
|
|
{
|
|
int32 bytes=1+strlen(argv);
|
|
|
|
velocirender_transmit ( vr_860args_action, argv, bytes, 0 );
|
|
}
|
|
|
|
|
|
/*}}} */
|
|
/*{{{ static i860_segment()*/
|
|
static void i860_segment ( FILE *fp, int32 bytes, vr_action action )
|
|
{
|
|
int32 n_read;
|
|
char *cp = (char *) __boot_packet;
|
|
int32 left=bytes;
|
|
|
|
#if (verbose)
|
|
printf ("i860 segment, expecting %ld bytes\n", bytes );
|
|
#endif
|
|
|
|
while (left > boot_packet_size ) {
|
|
link_io_ABORTCHECK;
|
|
n_read=fread ( cp, 1, boot_packet_size, fp );
|
|
if (n_read != boot_packet_size) {
|
|
printf ("i860 MNG file error, file corrupt or read error\n" );
|
|
return;
|
|
}
|
|
velocirender_packetize ( action, cp, boot_packet_size, 0 );
|
|
left-=boot_packet_size;
|
|
}
|
|
if (left != 0) {
|
|
link_io_ABORTCHECK;
|
|
n_read=fread ( cp, 1, (int32) left, fp );
|
|
if (n_read != left) {
|
|
printf ("i860 MNG file error, file corrupt or read error\n" );
|
|
return;
|
|
}
|
|
velocirender_packetize ( action, cp, n_read, 0 );
|
|
}
|
|
link_io_EXIT;
|
|
}
|
|
|
|
/*}}} */
|
|
|
|
/*{{{ static boot_860()*/
|
|
static void boot_860 ( char *f, char *argv )
|
|
{
|
|
FILE *fp;
|
|
int32 csize, dsize, bsize, cstart, dstart, bstart, entry;
|
|
char *cp=(char *) __boot_packet;
|
|
|
|
link_io_ABORTCHECK;
|
|
|
|
resetLoop( 5 );
|
|
|
|
#if verbose
|
|
printf ( "Calling i860_args\n" );
|
|
#endif
|
|
|
|
i860_args ( argv );
|
|
|
|
#if verbose
|
|
printf ( "Putting INT32 viz_860code\n" );
|
|
#endif
|
|
|
|
if ((fp=fopen(f, "rb" )) != 0) {
|
|
/* do csize, cstart etc.*/
|
|
/*{{{ */
|
|
#if verbose
|
|
printf ( "Putting 1st 7 words of mng\n" );
|
|
#endif
|
|
/*}}} */
|
|
/* note the 7 words are little-endian on disk, so fread, squirt is ok */
|
|
fread ( cp, 7, 4, fp ); /* read 7 ints, size 4*/
|
|
|
|
velocirender_transmit ( vr_860code_action, cp, 40, 0 );
|
|
|
|
link_io_ABORTCHECK;
|
|
|
|
cp = get_int32 ( cp, &csize );
|
|
cp = get_int32 ( cp, &dsize );
|
|
cp = get_int32 ( cp, &bsize );
|
|
cp = get_int32 ( cp, &cstart );
|
|
cp = get_int32 ( cp, &dstart );
|
|
cp = get_int32 ( cp, &bstart );
|
|
cp = get_int32 ( cp, &entry );
|
|
|
|
/*{{{ messgaes*/
|
|
#if (verbose)
|
|
printf ("csize <0x%lx> dsize <0x%lx> bsize <0x%lx>\n",
|
|
csize, dsize, bsize );
|
|
printf ("cstart <0x%lx> dstart <0x%lx> bstart <0x%lx> entry <0x%lx>\n",
|
|
cstart, dstart, bstart, entry );
|
|
#endif
|
|
/*}}} */
|
|
|
|
i860_segment ( fp, csize, vr_860code_action );
|
|
|
|
link_io_ABORTCHECK;
|
|
|
|
/*{{{ messages*/
|
|
#if (verbose)
|
|
printf ("i860 code segment loaded...\n");
|
|
#endif
|
|
/*}}} */
|
|
i860_segment ( fp, dsize, vr_860data_action );
|
|
|
|
link_io_ABORTCHECK;
|
|
|
|
/*{{{ messages*/
|
|
#if (verbose)
|
|
printf ("i860 data segment loaded...\n");
|
|
#endif
|
|
/*}}} */
|
|
i860_segment ( fp, bsize, vr_860bss_action );
|
|
|
|
link_io_ABORTCHECK;
|
|
|
|
/*{{{ messages*/
|
|
#if (verbose)
|
|
printf ("i860 bss segment loaded...\n");
|
|
#endif
|
|
/*}}} */
|
|
|
|
fclose (fp);
|
|
}
|
|
else {
|
|
/*{{{ */
|
|
#if verbose
|
|
printf ( "Failed to open i860 file\n" );
|
|
#endif
|
|
/*}}} */
|
|
printf ("Couldnt open i860 file %s\n", f );
|
|
return;
|
|
}
|
|
link_io_EXIT;
|
|
}
|
|
|
|
/*}}} */
|
|
|
|
/*{{{ static int32 getXputer(void)*/
|
|
static int32 getXputer(void)
|
|
{
|
|
char *str=getenv("TRANSPUTER");
|
|
|
|
if (str==NULL) return 0x150;
|
|
else {
|
|
int32 t;
|
|
|
|
if (sscanf(getenv("TRANSPUTER"), "%x", &t ) == 1)
|
|
return t;
|
|
else
|
|
return 0x150;
|
|
}
|
|
}
|
|
/*}}} */
|
|
|
|
/*}}} */
|
|
|
|
/*{{{ void vr_server ( char *tranny_name )*/
|
|
void vr_server ( char *tranny_name, int32 serve )
|
|
{
|
|
__blk=malloc(2048);
|
|
__boot_packet=malloc(2048);
|
|
|
|
setLA (0x150);
|
|
initLA();
|
|
|
|
#if verbose
|
|
printf("booting transputer with %s\n", tranny_name ); fflush(stdout);
|
|
#endif
|
|
boot_xputer ( tranny_name, 0 );
|
|
|
|
if (serve)
|
|
while (1)
|
|
startup_transaction();
|
|
}
|
|
/*}}} */
|
|
/*{{{ void start_velocirender ( char *tranny_name, char *hsp_name, char *i860_name,*/
|
|
|
|
void start_velocirender ( char *tranny_name,
|
|
char *hsp_name,
|
|
char *i860_name,
|
|
int32 XputerAddr,
|
|
int32 link_A,
|
|
int32 link_B,
|
|
int32 n_860s )
|
|
{
|
|
int32 ret, i;
|
|
|
|
__blk=malloc(2048);
|
|
__boot_packet=malloc(2048);
|
|
|
|
setLA (XputerAddr);
|
|
initLA();
|
|
|
|
#if verbose
|
|
printf("booting transputer at 0x%x with %s\n", XputerAddr, tranny_name ); fflush(stdout);
|
|
#endif
|
|
boot_xputer ( tranny_name, n_860s );
|
|
|
|
if (hsp_name != NULL) {
|
|
#if verbose
|
|
printf("booting HSP's ");
|
|
printf(" with %s\n", hsp_name ); fflush(stdout);
|
|
#endif
|
|
boot_HSP ( hsp_name, link_A, link_B );
|
|
}
|
|
if (i860_name != NULL) {
|
|
#if verbose
|
|
printf("booting i860 ");
|
|
printf("with %s\n", i860_name); fflush(stdout);
|
|
#endif
|
|
boot_860 ( i860_name, "i860 50MHz and kicking" );
|
|
}
|
|
#if verbose
|
|
printf("exiting start_dview\n"); fflush(stdout);
|
|
#endif
|
|
}
|
|
|
|
/*}}} */
|