2
* tfe.c - TFE ("The final ethernet" emulation.
2
* tfe.c - TFE ("The final ethernet") emulation.
5
* Spiro Trikaliotis <trik-news@gmx.de>
5
* Spiro Trikaliotis <Spiro.Trikaliotis@gmx.de>
7
7
* This file is part of VICE, the Versatile Commodore Emulator.
8
8
* See README for copyright notice.
47
51
/** #define TFE_DEBUG_DUMP 1 **/
53
/* #define TFE_DEBUG_FRAMES - might be defined in TFE.H! */
49
55
#define TFE_DEBUG_WARN 1 /* this should not be deactivated */
50
56
/** #define TFE_DEBUG_INIT 1 **/
51
57
/** #define TFE_DEBUG_LOAD 1 **/
55
61
/* ------------------------------------------------------------------------- */
56
62
/* variables needed */
65
This variable is used when we need to postpone the initialization
66
because tfe_init() is not yet called
68
static int should_activate = 0;
58
71
static log_t tfe_log = LOG_ERR;
60
73
/* status which received packages to accept
281
294
/* ------------------------------------------------------------------------- */
282
295
/* debugging functions */
297
#ifdef TFE_DEBUG_FRAMES
299
static int TfeDebugMaxFrameLengthToDump = 150;
301
char *debug_outbuffer(const int length, const unsigned char * const buffer)
303
#define MAXLEN_DEBUG 1600
306
static char outbuffer[MAXLEN_DEBUG*4+1];
309
assert( TfeDebugMaxFrameLengthToDump <= MAXLEN_DEBUG );
313
for (i=0; i<TfeDebugMaxFrameLengthToDump; i++) {
317
sprintf( p, "%02X%c", buffer[i], ((i+1)%16==0)?'*':(((i+1)%8==0)?'-':' '));
283
327
#ifdef TFE_DEBUG_DUMP
285
329
#define NUMBER_PER_LINE 8
349
393
/* ------------------------------------------------------------------------- */
350
394
/* initialization and deinitialization functions */
354
tfe_log = log_open("TFE");
356
if (!tfe_arch_init()) {
362
396
void tfe_reset(void)
398
if (tfe_enabled && !should_activate)
367
401
assert( tfe_packetpage );
423
int tfe_activate(void)
457
int tfe_activate_i(void)
425
459
assert( tfe == NULL );
426
460
assert( tfe_packetpage == NULL );
463
log_message( tfe_log, "tfe_activate_i()." );
428
466
/* allocate memory for visible IO register */
429
467
tfe = lib_malloc( TFE_COUNT_IO_REGISTER );
432
470
#ifdef TFE_DEBUG_INIT
433
log_message(tfe_log, "tfe_activate: Allocating tfe failed.");
471
log_message(tfe_log, "tfe_activate_i: Allocating tfe failed.");
452
490
#ifdef TFE_DEBUG_INIT
453
491
log_message(tfe_log, "tfe_activate: Allocated memory successfully.");
454
log_message(tfe_log, "\ttfe at 0x%08X, tfe_packetpage at 0x%08X", tfe, tfe_packetpage );
492
log_message(tfe_log, "\ttfe at $%08X, tfe_packetpage at $%08X", tfe, tfe_packetpage );
457
495
if (!tfe_arch_activate(tfe_interface)) {
505
/* virtually reset the LAN chip */
471
int tfe_deactivate(void)
512
int tfe_deactivate_i(void)
515
log_message( tfe_log, "tfe_deactivate_i()." );
473
518
assert(tfe && tfe_packetpage);
475
520
tfe_arch_deactivate();
530
int tfe_activate(void) {
532
log_message( tfe_log, "tfe_activate()." );
535
if (tfe_log != LOG_ERR) {
536
return tfe_activate_i();
545
int tfe_deactivate(void) {
547
log_message( tfe_log, "tfe_deactivate()." );
553
if (tfe_log != LOG_ERR)
554
return tfe_deactivate_i();
562
tfe_log = log_open("TFE");
564
if (!tfe_arch_init()) {
569
if (should_activate) {
571
if (tfe_activate() < 0) {
484
578
void tfe_shutdown(void)
486
580
assert( (tfe && tfe_packetpage) || (!tfe && !tfe_packetpage));
489
583
tfe_deactivate();
585
if (tfe_interface != NULL)
586
lib_free(tfe_interface);
512
/* This is a helper for tfe_should_accept(), since that one
516
unsigned long crc32(const char *buffer, unsigned int len)
520
unsigned long crc_result;
522
const char *pbuffer = buffer;
526
/* perform on every byte of the buffer */
527
for (i=0; i<len; i++ )
529
int act_byte = *pbuffer++;
532
/* now, perform on every bit of this byte */
535
int highest_bit = crc >> 31;
538
if (highest_bit ^ (act_byte & 1)) {
547
/* Unfortunately, our CRC has wrong order. Reverse it */
550
for (i=0; i<32; i++) {
551
crc_result = (crc_result << 1) | (crc & 1);
609
#ifdef TFE_DEBUG_FRAMES
610
#define return( _x_ ) \
614
log_message(tfe_log, "%s correct_mac=%u, broadcast=%u, multicast=%u, hashed=%u, hash_index=%u", (retval? "+++ ACCEPTED":"--- rejected"), *pcorrect_mac, *pbroadcast, *pmulticast, *phashed, *phash_index); \
559
621
This is a helper for tfe_receive() to determine if the received frame should be accepted
560
622
according to the settings.
572
634
/* first of all, delete any status */
574
637
*pcorrect_mac = 0;
641
#ifdef TFE_DEBUG_FRAMES
642
log_message(tfe_log, "tfe_should_accept called with %02X:%02X:%02X:%02X:%02X:%02X, length=%4u and buffer %s",
643
tfe_ia_mac[0], tfe_ia_mac[1], tfe_ia_mac[2],
644
tfe_ia_mac[3], tfe_ia_mac[4], tfe_ia_mac[5],
646
debug_outbuffer(length, buffer)
577
651
if ( buffer[0]==tfe_ia_mac[0]
578
652
&& buffer[1]==tfe_ia_mac[1]
605
679
/* broadcasts cannot be accepted by the hash filter */
606
return (tfe_recv_broadcast || tfe_recv_promiscuous) ? 1 : 0;
680
return((tfe_recv_broadcast || tfe_recv_promiscuous) ? 1 : 0);
609
683
/* now check if DA passes the hash filter */
610
hashreg = (crc32(buffer,6) >> 26) & 0x3F;
684
hashreg = (~crc32_buf(buffer,6) >> 26) & 0x3F;
612
686
*phashed = (tfe_hash_mask[(hashreg>=32)?1:0] & (1 << (hashreg&0x1F))) ? 1 : 0;
625
return (tfe_recv_multicast || tfe_recv_promiscuous) ? 1 : 0;
699
return((tfe_recv_multicast || tfe_recv_promiscuous) ? 1 : 0);
627
return (tfe_recv_hashfilter || tfe_recv_promiscuous) ? 1 : 0;
701
return((tfe_recv_hashfilter || tfe_recv_promiscuous) ? 1 : 0);
630
return tfe_recv_promiscuous ? 1 : 0;
704
return(tfe_recv_promiscuous ? 1 : 0);
707
#ifdef TFE_DEBUG_FRAMES
634
712
WORD tfe_receive(void)
670
754
if (hashed || correct_mac || broadcast) {
671
755
/* we already know the type of frame: Trust it! */
756
#ifdef TFE_DEBUG_FRAMES
757
log_message( tfe_log, "+++ tfe_receive(): *** hashed=%u, correct_mac=%u, "
758
"broadcast=%u", hashed, correct_mac, broadcast);
674
762
/* determine ourself the type of frame */
755
848
/* clear BusST */
756
849
SET_PP_16(TFE_PP_ADDR_SE_BUSST, busst & ~0x180);
851
#ifdef TFE_DEBUG_FRAMES
852
log_message(tfe_log, "tfe_arch_transmit() called with: "
853
"length=%4u and buffer %s", txlen,
854
debug_outbuffer(txlen, &tfe_packetpage[TFE_PP_ADDR_TX_FRAMELOC])
758
858
tfe_arch_transmit(
759
859
txcmd & 0x0100 ? 1 : 0, /* FORCE: Delete waiting frames in transmit buffer */
760
860
txcmd & 0x0200 ? 1 : 0, /* ONECOLL: Terminate after just one collision */
1056
1156
case TFE_ADDR_PP_DATA+1:
1057
1157
/* make sure the TFE register have the correct content */
1059
WORD ppaddress = tfe_packetpage_ptr;
1061
if (ppaddress >= MAX_PACKETPAGE_ARRAY)
1063
/* FIXME: @SRT What is the real behaviour in such condition? */
1064
#ifdef TFE_DEBUG_WARN
1065
log_message(tfe_log,
1066
"WARNING! Reading PacketPage beyond MAX_PACKETPAGE_ARRAY: %04X"
1067
"Performing \"wrap around\".", ppaddress);
1069
ppaddress &= MAX_PACKETPAGE_ARRAY-1;
1159
WORD ppaddress = tfe_packetpage_ptr & (MAX_PACKETPAGE_ARRAY-1);
1072
1161
/* perform side-effects the read may perform */
1073
1162
tfe_sideeffects_read_pp( ppaddress );
1075
1164
/* [3] make sure the data matches the real value - [1] assumes this! */
1076
SET_TFE_16( TFE_ADDR_PP_DATA, GET_PP_16(ppaddress) );
1165
SET_TFE_16( TFE_ADDR_PP_DATA, GET_PP_16(ppaddress) );
1080
1169
#ifdef TFE_DEBUG_LOAD
1081
log_message(tfe_log, "reading PP Ptr: 0x%04X => 0x%04X.",
1170
log_message(tfe_log, "reading PP Ptr: $%04X => $%04X.",
1082
1171
tfe_packetpage_ptr, GET_PP_16(tfe_packetpage_ptr) );
1200
1289
tfe_packetpage_ptr = GET_TFE_16(TFE_ADDR_PP_PTR);
1202
1291
#ifdef TFE_DEBUG_STORE
1203
log_message(tfe_log, "set PP Ptr to 0x%04X.", tfe_packetpage_ptr);
1292
log_message(tfe_log, "set PP Ptr to $%04X.", tfe_packetpage_ptr);
1295
if ((tfe_packetpage_ptr & 1) != 0) {
1297
#ifdef TFE_DEBUG_WARN
1298
log_message(tfe_log,
1299
"WARNING! PacketPage register set to odd address $%04X (not allowed!)",
1300
tfe_packetpage_ptr );
1301
#endif /* #ifdef TFE_DEBUG_WARN */
1303
/* "correct" the address to the next lower address
1304
REMARK: I don't know how a real cs8900a will behave in this case,
1305
since it is not allowed. Nevertheless, this "correction"
1306
prevents assert()s to fail.
1308
tfe_packetpage_ptr -= 1;
1207
1312
[1] The TFE_ADDR_PP_DATA does not need to be modified here,
1208
1313
since it will be modified just before a read or store operation
1214
1319
case TFE_ADDR_PP_DATA:
1215
1320
case TFE_ADDR_PP_DATA+1:
1323
WORD ppaddress = tfe_packetpage_ptr & (MAX_PACKETPAGE_ARRAY-1);
1216
1325
#ifdef TFE_DEBUG_STORE
1217
log_message(tfe_log, "before writing to PP Ptr: 0x%04X <= 0x%04X.",
1218
tfe_packetpage_ptr, GET_PP_16(tfe_packetpage_ptr) );
1222
WORD ppaddress = tfe_packetpage_ptr;
1224
if (ppaddress >= MAX_PACKETPAGE_ARRAY)
1226
/* FIXME: @SRT What is the real behaviour in such condition? */
1227
#ifdef TFE_DEBUG_WARN
1228
log_message(tfe_log,
1229
"WARNING! Writing PacketPage beyond MAX_PACKETPAGE_ARRAY: %04X."
1230
"Performing \"wrap around\".", ppaddress);
1232
ppaddress &= MAX_PACKETPAGE_ARRAY-1;
1326
log_message(tfe_log, "before writing to PP Ptr: $%04X <= $%04X.",
1327
ppaddress, GET_PP_16(ppaddress) );
1236
1330
register WORD tmpIoAddr = ioaddress & ~1; /* word-align the address */
1237
SET_PP_16(tfe_packetpage_ptr, GET_TFE_16(tmpIoAddr));
1331
SET_PP_16(ppaddress, GET_TFE_16(tmpIoAddr));
1240
1334
/* perform side-effects the write may perform */
1241
1335
/* the addresses are always aligned on the whole 16-bit-word */
1242
tfe_sideeffects_write_pp(tfe_packetpage_ptr, ioaddress-TFE_ADDR_PP_DATA);
1336
tfe_sideeffects_write_pp(ppaddress, ioaddress-TFE_ADDR_PP_DATA);
1246
1338
#ifdef TFE_DEBUG_STORE
1247
log_message(tfe_log, "after writing to PP Ptr: 0x%04X <= 0x%04X.",
1248
tfe_packetpage_ptr, GET_PP_16(tfe_packetpage_ptr) );
1339
log_message(tfe_log, "after writing to PP Ptr: $%04X <= $%04X.",
1340
ppaddress, GET_PP_16(ppaddress) );
1257
1350
/* ------------------------------------------------------------------------- */
1258
1351
/* resources support functions */
1352
static const c64export_resource_t export_res = {
1261
1357
int set_tfe_disabled(resource_value_t v, void *param)
1360
1465
(void *)&tfe_enabled, set_tfe_enabled, NULL },
1361
1466
{ "ETHERNET_AS_RR", RES_INTEGER, (resource_value_t)0,
1362
1467
(void *)&tfe_as_rr_net, set_tfe_rr_net, NULL },
1363
{ "ETHERNET_INTERFACE", RES_STRING, (resource_value_t)"",
1468
{ "ETHERNET_INTERFACE", RES_STRING,
1469
(resource_value_t)ARCHDEP_ETHERNET_DEFAULT_DEVICE,
1364
1470
(void *)&tfe_interface, set_tfe_interface, NULL },