Skip to content

Commit

Permalink
Hook up Ethernet JS API to SheepShaver
Browse files Browse the repository at this point in the history
Mostly a matter of bridging the Basilisk II ethernet APIs to
SheepShaver's, similar to ether_unix.cpp. Two gotchas that were
encountered:
- SheepShaver's PRAM is offset by 0x1300 bytes, so toggling of the
  preferences to enable AppleTalk at boot time had to be adjusted.
- We can end up trying to process an Ethernet packet before the driver
  is initialized, which leads to a segfault. Add a guard for
  ether_driver_opened (and in that case drop the packet on the floor).

This is enough to make Marathon network play work under System 7.5.3,
but it does not work under Mac OS 9.

Updates mihaip/infinite-mac#34
  • Loading branch information
mihaip committed Nov 11, 2022
1 parent 0c0baef commit f92a354
Show file tree
Hide file tree
Showing 10 changed files with 134 additions and 32 deletions.
34 changes: 34 additions & 0 deletions BasiliskII/src/CrossPlatform/ether_helpers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#ifndef ETHER_HELPERS_H
#define ETHER_HELPERS_H

/*
* Check whether Ethernet address is AppleTalk or Ethernet broadcast address
*/

static inline bool is_apple_talk_broadcast(uint8 *p) {
return p[0] == 0x09 && p[1] == 0x00 && p[2] == 0x07 && p[3] == 0xff &&
p[4] == 0xff && p[5] == 0xff;
}

static inline bool is_ethernet_broadcast(uint8 *p) {
return p[0] == 0xff && p[1] == 0xff && p[2] == 0xff && p[3] == 0xff &&
p[4] == 0xff && p[5] == 0xff;
}

static void enable_apple_talk_in_pram(uint8 *XPRAM) {
// node ID hint for printer port (AppleTalk)
XPRAM[0x12] = 0x01;
// serial ports config bits: 4-7 A, 0-3 B
// useFree 0 Use undefined
// useATalk 1 AppleTalk
// useAsync 2 Async
// useExtClk 3 externally clocked
XPRAM[0x13] = 0x20;
// AppleTalk Zone name ("*")
XPRAM[0xbd] = 0x01;
XPRAM[0xbe] = 0x2a;
// AppleTalk Network Number
XPRAM[0xde] = 0xff;
}

#endif /* ETHER_HELPERS_H */
89 changes: 88 additions & 1 deletion BasiliskII/src/Unix/JS/ether_js.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,25 @@
#include "cpu_emulation.h"
#include "ether.h"
#include "ether_defs.h"
#include "ether_helpers.h"
#include "macos_util.h"
#include "main.h"
#include "prefs.h"

#define DEBUG 0
#include "debug.h"

#ifdef SHEEPSHAVER
static bool net_open = false; // Flag: initialization succeeded, network device open
static uint8 ether_addr[6]; // Our Ethernet address

// Error codes
enum { eMultiErr = -91, eLenErr = -92, lapProtErr = -94, excessCollsns = -95 };

#define ether_wds_to_buffer ether_msgb_to_buffer

#endif

static const uint8 GENERATED_ETHER_ADDR_PREFIX = 0xb2;

// Attached network protocols, maps protocol type to MacOS handler address
Expand All @@ -25,6 +38,8 @@ static void ether_addr_to_str(uint8* ether_addr, char* ether_addr_str) {
ether_addr[2], ether_addr[3], ether_addr[4], ether_addr[5]);
}

#ifndef SHEEPSHAVER

// Dispatch packet to protocol handler
static void ether_dispatch_packet(uint32 p, uint32 length) {
// Get packet type
Expand Down Expand Up @@ -64,6 +79,8 @@ static void ether_dispatch_packet(uint32 p, uint32 length) {
Execute68k(handler, &r);
}

#endif

bool ether_init(void) {
// Construct random Ethernet address. JS has access to a better random
// number generator, use that to seed.
Expand Down Expand Up @@ -165,7 +182,77 @@ void EtherInterrupt(void) {
if (length < 14) {
return;
}

#ifdef SHEEPSHAVER
if (!ether_driver_opened) {
// We can't dispatch packets before the ethernet driver is initialized
// (ether_dispatch_packet_tvect is not initialized yet), don't do anything
// for now.
D(bug("Dropping Ethernet packet of %d bytes, driver has not been opened yet\n", length));
continue;
}
#endif
ether_dispatch_packet(packet, length);
}
}

// SheepShaver glue
#ifdef SHEEPSHAVER

void EtherInit(void) {
net_open = false;

if (PrefsFindBool("nonet")) {
return;
}

net_open = ether_init();
}

void EtherExit(void) {
ether_exit();
net_open = false;
}

void AO_get_ethernet_address(uint32 arg) {
uint8* addr = Mac2HostAddr(arg);
if (net_open)
OTCopy48BitAddress(ether_addr, addr);
else {
addr[0] = 0x12;
addr[1] = 0x34;
addr[2] = 0x56;
addr[3] = 0x78;
addr[4] = 0x9a;
addr[5] = 0xbc;
}
D(bug("AO_get_ethernet_address: got address %02x%02x%02x%02x%02x%02x\n", addr[0], addr[1],
addr[2], addr[3], addr[4], addr[5]));
}

void AO_enable_multicast(uint32 addr) {
// No-op
}

void AO_disable_multicast(uint32 addr) {
// No-op
}

void AO_transmit_packet(uint32 mp) {
if (net_open) {
switch (ether_write(mp)) {
case noErr:
num_tx_packets++;
break;
case excessCollsns:
num_tx_buffer_full++;
break;
}
}
}

void EtherIRQ(void) {
num_ether_irq++;
EtherInterrupt();
}

#endif // SHEEPSHAVER
1 change: 1 addition & 0 deletions BasiliskII/src/ether.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include "prefs.h"
#include "ether.h"
#include "ether_defs.h"
#include "ether_helpers.h"

#ifndef NO_STD_NAMESPACE
using std::map;
Expand Down
17 changes: 0 additions & 17 deletions BasiliskII/src/include/ether.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,21 +93,4 @@ static inline int ether_wds_to_buffer(uint32 wds, uint8 *p)
return len;
}

/*
* Check whether Ethernet address is AppleTalk or Ethernet broadcast address
*/

static inline bool is_apple_talk_broadcast(uint8 *p)
{
return p[0] == 0x09 && p[1] == 0x00 && p[2] == 0x07
&& p[3] == 0xff && p[4] == 0xff && p[5] == 0xff;
}

static inline bool is_ethernet_broadcast(uint8 *p)
{
return p[0] == 0xff && p[1] == 0xff && p[2] == 0xff
&& p[3] == 0xff && p[4] == 0xff && p[5] == 0xff;
}


#endif
15 changes: 2 additions & 13 deletions BasiliskII/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "video.h"
#include "serial.h"
#include "ether.h"
#include "ether_helpers.h"
#include "clip.h"
#include "adb.h"
#include "rom_patches.h"
Expand Down Expand Up @@ -133,19 +134,7 @@ bool InitAll(const char *vmdir)
}

if (PrefsFindBool("appletalk")) {
// node ID hint for printer port (AppleTalk)
XPRAM[0x12] = 0x01;
// serial ports config bits: 4-7 A, 0-3 B
// useFree 0 Use undefined
// useATalk 1 AppleTalk
// useAsync 2 Async
// useExtClk 3 externally clocked
XPRAM[0x13] = 0x20;
// AppleTalk Zone name ("*")
XPRAM[0xbd] = 0x01;
XPRAM[0xbe] = 0x2a;
// AppleTalk Network Number
XPRAM[0xde] = 0xff;
enable_apple_talk_in_pram(XPRAM);
}

// Set boot volume
Expand Down
1 change: 1 addition & 0 deletions SheepShaver/src/CrossPlatform/ether_helpers.h
1 change: 1 addition & 0 deletions SheepShaver/src/Unix/JS/ether_js.cpp
2 changes: 1 addition & 1 deletion SheepShaver/src/Unix/configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,7 @@ if [[ "x$WANT_EMSCRIPTEN" = "xyes" ]]; then
VIDEOSRCS="JS/video_js.cpp SpookyV2.cpp"
SERIALSRC=../dummy/serial_dummy.cpp
SCSISRC=../dummy/scsi_dummy.cpp
ETHERSRC=../dummy/ether_dummy.cpp
ETHERSRC=JS/ether_js.cpp
AUDIOSRC=JS/audio_js.cpp
EXTRASYSSRCS="$EXTRASYSSRCS JS/input_js.cpp JS/clip_js.cpp"
AC_DEFINE(EMSCRIPTEN, 1, [Define if targeting Emscripten.])
Expand Down
5 changes: 5 additions & 0 deletions SheepShaver/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "video.h"
#include "audio.h"
#include "ether.h"
#include "ether_helpers.h"
#include "serial.h"
#include "clip.h"
#include "extfs.h"
Expand Down Expand Up @@ -106,6 +107,10 @@ bool InitAll(const char *vmdir)
XPRAM[0x138a] = 0x25; // Use PPC memory manager ("Modern Memory Manager")
}

if (PrefsFindBool("appletalk")) {
enable_apple_talk_in_pram(XPRAM + 0x1300);
}

// Set boot volume
int16 i16 = PrefsFindInt32("bootdrive");
XPRAM[0x1378] = i16 >> 8;
Expand Down
1 change: 1 addition & 0 deletions SheepShaver/src/prefs_items.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ prefs_desc common_prefs_items[] = {
{"title", TYPE_STRING, false, "window title"},
{"sound_buffer", TYPE_INT32, false, "sound buffer length"},
{"name_encoding", TYPE_INT32, false, "file name encoding"},
{"appletalk", TYPE_BOOLEAN, false, "enable AppleTalk in default PRAM"},
{"jsfrequentreadinput", TYPE_BOOLEAN, false, "Read JS input frequently (multiple times per tick) to reduce latency"},
{NULL, TYPE_END, false, NULL} // End of list
};
Expand Down

0 comments on commit f92a354

Please sign in to comment.