Skip to content

Commit 41c8a4c

Browse files
committed
MEGA65: ethernet changes preparations #242
No significant change (or working state) ... yet
1 parent daeff74 commit 41c8a4c

File tree

4 files changed

+60
-67
lines changed

4 files changed

+60
-67
lines changed

targets/mega65/ethernet65.c

Lines changed: 46 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* A work-in-progess MEGA65 (Commodore 65 clone origins) emulator
22
Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
3-
Copyright (C)2018 LGB (Gábor Lénárt) <[email protected]>
3+
Copyright (C)2018,2025 LGB (Gábor Lénárt) <[email protected]>
44
55
This program is free software; you can redistribute it and/or modify
66
it under the terms of the GNU General Public License as published by
@@ -60,10 +60,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
6060
#define SELECT_WAIT_USEC_MIN 5
6161
#define SELECT_WAIT_INC_VAL 5
6262

63-
6463
#define ETH_II_FRAME_ARP 0x0806
6564
#define ETH_II_FRAME_IPV4 0x0800
6665

66+
#define RX_BUFFERS 4
67+
68+
6769
static int eth_debug;
6870

6971
static volatile struct {
@@ -91,17 +93,18 @@ static volatile struct {
9193
int adjust_txd_phase;
9294
int miim_register;
9395
int phy_number;
94-
Uint8 rx_buffer[0x1000]; // actually, two 2048 bytes long buffers in one array
95-
Uint8 tx_buffer[0x0800]; // a 2048 bytes long buffer to TX
9696
} eth65;
9797

98+
static Uint8 rx_buffer[0x1000]; // actually, two 2048 bytes long buffers in one array
99+
static Uint8 tx_buffer[0x0800]; // a 2048 bytes long buffer to TX
98100

99101
static Uint8 mac_address[6] = {0x02,0x47,0x53,0x65,0x65,0x65}; // 00:80:10:... would be nicer, though a bit of cheating, it belongs to Commodore International(TM).
100102
#ifdef HAVE_ETHERTAP
101103
static const Uint8 mac_bcast[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; // also used as IPv4 bcast detection with filters, if only the first 4 bytes are checked
102104
#endif
103105

104106
static Uint16 miimlo8[0x20], miimhi8[0x20];
107+
static Uint8 eth_regs[0x10];
105108

106109
#ifndef ETH65_NO_DEBUG
107110
#define ETHDEBUG(...) do { \
@@ -150,11 +153,10 @@ static const char init_error_prefix[] = "ETH: disabled: ";
150153

151154
static SDL_Thread *thread_id = NULL;
152155

153-
static XEMU_INLINE int ethernet_rx_processor ( void )
156+
static inline int ethernet_rx_processor ( void )
154157
{
155158
Uint8 rx_temp_buffer[0x800];
156-
int ethertype, ret;
157-
ret = xemu_tuntap_read(rx_temp_buffer, 6 + 6 + 2, sizeof rx_temp_buffer);
159+
const int ret = xemu_tuntap_read(rx_temp_buffer, 6 + 6 + 2, sizeof rx_temp_buffer);
158160
if (ret == -2) {
159161
eth65.select_wait_usec = 1000000; // serious problem, do 1sec wait ...
160162
ETHDEBUG("ETH-THREAD: read with EAGAIN, continue ..." NL);
@@ -185,7 +187,7 @@ static XEMU_INLINE int ethernet_rx_processor ( void )
185187
}
186188
// XEMU stuff, just to test TAP
187189
// it only recoginizes Ethernet-II frames, for frame types IPv4 or ARP
188-
ethertype = (rx_temp_buffer[12] << 8) | rx_temp_buffer[13];
190+
const int ethertype = (rx_temp_buffer[12] << 8) | rx_temp_buffer[13];
189191
if (ethertype < 1536) {
190192
ETHDEBUG("ETH-THREAD: ... however, skipped by XEMU: not an Ethernet-II frame ($%04X)" NL, ethertype);
191193
return 0;
@@ -228,11 +230,11 @@ static XEMU_INLINE int ethernet_rx_processor ( void )
228230
ETHDEBUG("ETH-THREAD: ... MEGA[65]-COOL: we are ready to propogate packet" NL);
229231
// M65 stores the received frame size in "6502 byte order" as the first two bytes in the RX
230232
// (this makes things somewhat non-symmetric, as for TX, the size are in a pair of registers)
231-
eth65.rx_buffer[eth65.rx_buffer_using] = ret & 0xFF;
232-
eth65.rx_buffer[eth65.rx_buffer_using + 1] = ret >> 8;
233+
rx_buffer[eth65.rx_buffer_using] = ret & 0xFF;
234+
rx_buffer[eth65.rx_buffer_using + 1] = ret >> 8;
233235
for (int i = 0; i < ret; i++)
234-
eth65.rx_buffer[eth65.rx_buffer_using + 2 + i] = rx_temp_buffer[i];
235-
//memcpy(eth65.rx_buffer + eth65.rx_buffer_using + 2, rx_temp_buffer, r);
236+
rx_buffer[eth65.rx_buffer_using + 2 + i] = rx_temp_buffer[i];
237+
//memcpy(rx_buffer + eth65.rx_buffer_using + 2, rx_temp_buffer, r);
236238
eth65.rx_enabled = 0; // disable RX till user not ACK'ed by swapping RX buffers
237239
RX_IRQ_ON(); // signal, that we have something! we don't support IRQs yet, but it's also used for polling!
238240
return 0;
@@ -241,7 +243,6 @@ static XEMU_INLINE int ethernet_rx_processor ( void )
241243

242244
static XEMU_INLINE int ethernet_tx_processor ( void )
243245
{
244-
int ret, size;
245246
if (eth65.tx_size < 14 || eth65.tx_size > ETH_FRAME_MAX_SIZE) {
246247
ETHDEBUG("ETH-THREAD: skipping TX, because invalid frame size: %d" NL, eth65.tx_size);
247248
// still fake an OK answer FIXME ?
@@ -250,14 +251,15 @@ static XEMU_INLINE int ethernet_tx_processor ( void )
250251
return 0;
251252
}
252253
#if 0
254+
int size;
253255
// maybe this is not needed, and TAP device can handle autmatically, but anyway
254256
if (eth65.tx_size < ETH_FRAME_MIN_SIZE) {
255-
memset((void*)eth65.tx_buffer + eth65.tx_size, 0, ETH_FRAME_MIN_SIZE - eth65.tx_size);
257+
memset((void*)tx_buffer + eth65.tx_size, 0, ETH_FRAME_MIN_SIZE - eth65.tx_size);
256258
size = ETH_FRAME_MIN_SIZE;
257259
} else
258260
#endif
259-
size = eth65.tx_size;
260-
ret = xemu_tuntap_write((void*)eth65.tx_buffer, size);
261+
const int size = eth65.tx_size;
262+
const int ret = xemu_tuntap_write((void*)tx_buffer, size);
261263
if (ret == -2) { // FIXME: with read OK, but for write????
262264
eth65.select_wait_usec = 1000000; // serious problem, do 1sec wait ...
263265
ETHDEBUG("ETH-THREAD: write with EAGAIN, continue ..." NL);
@@ -284,12 +286,10 @@ static XEMU_INLINE int ethernet_tx_processor ( void )
284286
}
285287

286288

287-
288289
static int ethernet_thread ( void *unused )
289290
{
290291
ETHDEBUG("ETH-THREAD: hello from the thread." NL);
291292
while (eth65.enabled) {
292-
int ret;
293293
/* ------------------- check for RX condition ------------------- */
294294
if (
295295
(!eth65.rx_enabled) && eth65.no_reset &&
@@ -309,7 +309,7 @@ static int ethernet_thread ( void *unused )
309309
eth65.select_wait_usec += SELECT_WAIT_INC_VAL;
310310
}
311311
/* ------------------- The select() stuff ------------------- */
312-
ret = xemu_tuntap_select(((eth65.rx_enabled && eth65.no_reset) ? XEMU_TUNTAP_SELECT_R : 0) | ((eth65.tx_trigger && eth65.no_reset) ? XEMU_TUNTAP_SELECT_W : 0), eth65.select_wait_usec);
312+
const int ret = xemu_tuntap_select(((eth65.rx_enabled && eth65.no_reset) ? XEMU_TUNTAP_SELECT_R : 0) | ((eth65.tx_trigger && eth65.no_reset) ? XEMU_TUNTAP_SELECT_W : 0), eth65.select_wait_usec);
313313
//ETHDEBUG("ETH-THREAD: after select with %d usecs, retval = %d, rx_enabled = %d, tx_trigger = %d" NL,
314314
// eth65.select_wait_usec, ret, eth65.rx_enabled, eth65.tx_trigger
315315
//);
@@ -349,10 +349,11 @@ static int ethernet_thread ( void *unused )
349349
however we want to keep them, so a network-aware software won't go crazy on totally missing register-level emulation */
350350

351351

352-
Uint8 eth65_read_reg ( int addr )
352+
// "addr" must be between $0 and $F !!!
353+
Uint8 eth65_read_reg ( const unsigned int addr )
353354
{
354-
DEBUG("ETH: reading register $%02X" NL, addr & 0xF);
355-
switch (addr & 0xF) {
355+
DEBUG("ETH: reading register $%02X" NL, addr);
356+
switch (addr) {
356357
/* **** $D6E0 register **** */
357358
case 0x00:
358359
return eth65.no_reset; // FIXME: not other bits emulated yet here
@@ -380,6 +381,8 @@ Uint8 eth65_read_reg ( int addr )
380381
case 0x02: return eth65.tx_size & 0xFF;
381382
/* **** $D6E3 register: TX size register high (4 bits only) **** */
382383
case 0x03: return (eth65.tx_size >> 8) & 0xFF; // 4 bits, but tx_size var cannot contain more anyway
384+
/* **** $D6E4 register: on _reading_ it seems to gives back the total number of RX buffers what system has *** */
385+
case 0x04: return RX_BUFFERS;
383386
/* **** $D6E5 register **** */
384387
case 0x05:
385388
return
@@ -401,24 +404,20 @@ Uint8 eth65_read_reg ( int addr )
401404
/* **** $D6E8 register **** */
402405
case 0x08: return miimhi8[eth65.miim_register];
403406
/* **** $D6E9 - $D6EE registers: MAC address **** */
404-
case 0x09: return mac_address[0];
405-
case 0x0A: return mac_address[1];
406-
case 0x0B: return mac_address[2];
407-
case 0x0C: return mac_address[3];
408-
case 0x0D: return mac_address[4];
409-
case 0x0E: return mac_address[5];
407+
case 0x09: case 0x0A: case 0x0B: case 0x0C: case 0x0D: case 0x0E:
408+
return mac_address[addr - 9];
410409
default:
411410
return 0xFF;
412411
}
413412
}
414413

415414

416-
417-
418-
void eth65_write_reg ( int addr, Uint8 data )
415+
// "addr" must be between $0 and $F !!!
416+
void eth65_write_reg ( const unsigned int addr, const Uint8 data )
419417
{
420-
DEBUG("ETH: writing register $%02X with data $%02X" NL, addr & 0xF, data);
421-
switch (addr & 0xF) {
418+
eth_regs[addr] = data;
419+
DEBUG("ETH: writing register $%02X with data $%02X" NL, addr, data);
420+
switch (addr) {
422421
/* **** $D6E0 register **** */
423422
case 0x00:
424423
eth65.no_reset = (data & 0x01); // FIXME: it seems to be the same as $D6E1 bit0???
@@ -493,30 +492,29 @@ void eth65_write_reg ( int addr, Uint8 data )
493492
miimhi8[eth65.miim_register] = data;
494493
break;
495494
/* **** $D6E9 - $D6EE registers: MAC address **** */
496-
case 0x09: mac_address[0] = data; break;
497-
case 0x0A: mac_address[1] = data; break;
498-
case 0x0B: mac_address[2] = data; break;
499-
case 0x0C: mac_address[3] = data; break;
500-
case 0x0D: mac_address[4] = data; break;
501-
case 0x0E: mac_address[5] = data; break;
495+
case 0x09: case 0x0A: case 0x0B: case 0x0C: case 0x0D: case 0x0E:
496+
mac_address[addr - 9] = data;
497+
break;
502498
}
503499
}
504500

505501

506-
507-
Uint8 eth65_read_rx_buffer ( int offset )
502+
// Note: "offset" shouldn't be trusted fully *EVER*, only its lower 11 bits (0-$7FF)
503+
// Though, this is used by memory_mapper.c where the parameter is "addr32" (physical address),
504+
// here we re-use this functionality with io_mapper.c
505+
Uint8 eth65_buffer_reader ( const Uint32 offset )
508506
{
509507
// FIXME what happens if M65 receives frame but user switches buffer meanwhile. Not so nice :-O
510-
return eth65.rx_buffer[eth65.rx_buffer_mapped + (offset & 0x7FF)];
508+
return rx_buffer[eth65.rx_buffer_mapped + (offset & 0x7FFU)];
511509
}
512510

513-
void eth65_write_tx_buffer ( int offset, Uint8 data )
511+
// See the note before eth65_buffer_reader()
512+
void eth65_buffer_writer ( const Uint32 offset, const Uint8 data )
514513
{
515-
eth65.tx_buffer[offset & 0x7FF] = data;
514+
tx_buffer[offset & 0x7FFU] = data;
516515
}
517516

518517

519-
520518
void eth65_shutdown ( void )
521519
{
522520
if (eth65.exited)
@@ -540,13 +538,14 @@ void eth65_shutdown ( void )
540538
// This is not the reset what eth65.no_reset stuff does, but reset of M65 (also called by eth65_init)
541539
void eth65_reset ( void )
542540
{
541+
memset(&eth_regs, 0, sizeof eth_regs);
543542
memset(&miimlo8, 0, sizeof miimlo8);
544543
memset(&miimhi8, 0, sizeof miimhi8);
545544
memset((void*)&eth65, 0, sizeof eth65);
546545
RX_IRQ_OFF();
547546
TX_IRQ_OFF();
548-
memset((void*)eth65.rx_buffer, 0xFF, sizeof eth65.rx_buffer);
549-
memset((void*)eth65.tx_buffer, 0xFF, sizeof eth65.tx_buffer);
547+
memset((void*)rx_buffer, 0xFF, sizeof rx_buffer);
548+
memset((void*)tx_buffer, 0xFF, sizeof tx_buffer);
550549
eth65.select_wait_usec = SELECT_WAIT_USEC_MAX;
551550
eth65.rx_buffer_using = 0x800; // RX buffer is used to RX @ ofs 0
552551
eth65.rx_buffer_mapped = 0x000; // RX buffer mapped @ ofs 0

targets/mega65/ethernet65.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* A work-in-progess MEGA65 (Commodore 65 clone origins) emulator
22
Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
3-
Copyright (C)2018 LGB (Gábor Lénárt) <[email protected]>
3+
Copyright (C)2018,2025 LGB (Gábor Lénárt) <[email protected]>
44
55
This program is free software; you can redistribute it and/or modify
66
it under the terms of the GNU General Public License as published by
@@ -16,15 +16,15 @@ You should have received a copy of the GNU General Public License
1616
along with this program; if not, write to the Free Software
1717
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
1818

19-
#ifndef __XEMU_ETHERNET65_MEGA65_H_INCLUDED
20-
#define __XEMU_ETHERNET65_MEGA65_H_INCLUDED
19+
#ifndef XEMU_MEGA65_ETHERNET65_H_INCLUDED
20+
#define XEMU_MEGA65_ETHERNET65_H_INCLUDED
2121

22-
extern int eth65_init ( const char *options );
22+
extern int eth65_init ( const char *options );
2323
extern void eth65_shutdown ( void );
2424
extern void eth65_reset ( void );
25-
extern Uint8 eth65_read_rx_buffer ( int offset );
26-
extern void eth65_write_tx_buffer ( int offset, Uint8 data );
27-
extern Uint8 eth65_read_reg ( int addr );
28-
extern void eth65_write_reg ( int addr , Uint8 data );
25+
extern Uint8 eth65_buffer_reader ( const Uint32 offset );
26+
extern void eth65_buffer_writer ( const Uint32 offset, const Uint8 data );
27+
extern Uint8 eth65_read_reg ( const unsigned int addr );
28+
extern void eth65_write_reg ( const unsigned int addr, const Uint8 data );
2929

3030
#endif

targets/mega65/io_mapper.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ Uint8 io_read ( unsigned int addr )
274274
if (addr >= 0x80 && addr <= 0x93) // SDcard controller etc of MEGA65
275275
return sdcard_read_register(addr - 0x80);
276276
if ((addr & 0xF0) == 0xE0)
277-
return eth65_read_reg(addr);
277+
return eth65_read_reg(addr & 0xF);
278278
switch (addr) {
279279
case 0x7C:
280280
return 0; // emulate the "UART is ready" situation (used by some HICKUPs around from v0.11 or so)
@@ -372,7 +372,7 @@ Uint8 io_read ( unsigned int addr )
372372
/* $D800-$DFFF: in case of ethernet I/O mode only! */
373373
/* ----------------------------------------------- */
374374
case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F:
375-
return eth65_read_rx_buffer(addr - 0x2800);
375+
return eth65_buffer_reader(addr);
376376
/* ----------------------- */
377377
/* $D800-$DBFF: COLOUR RAM */
378378
/* ----------------------- */
@@ -551,7 +551,7 @@ void io_write ( unsigned int addr, Uint8 data )
551551
return;
552552
}
553553
if ((addr & 0xF0) == 0xE0) {
554-
eth65_write_reg(addr, data);
554+
eth65_write_reg(addr & 0xF, data);
555555
return;
556556
}
557557
if (addr == 0xF4) { // audio mixer co-efficient address
@@ -639,7 +639,7 @@ void io_write ( unsigned int addr, Uint8 data )
639639
/* $D800-$DFFF: in case of ethernet I/O mode only! */
640640
/* ----------------------------------------------- */
641641
case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F:
642-
eth65_write_tx_buffer(addr - 0x2800, data);
642+
eth65_buffer_writer(addr, data);
643643
return;
644644
/* ----------------------- */
645645
/* $D800-$DBFF: COLOUR RAM */

targets/mega65/memory_mapper.c

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -248,12 +248,6 @@ static Uint8 disk_buffer_user_reader ( const Uint32 addr32 ) {
248248
static void disk_buffer_user_writer ( const Uint32 addr32, const Uint8 data ) {
249249
disk_buffer_cpu_view[(addr32 - 0xFFD6000U) & 0x1FF] = data;
250250
}
251-
static Uint8 eth_buffer_reader ( const Uint32 addr32 ) {
252-
return eth65_read_rx_buffer(addr32 - 0xFFDE800U);
253-
}
254-
static void eth_buffer_writer ( const Uint32 addr32, const Uint8 data ) {
255-
eth65_write_tx_buffer(addr32 - 0xFFDE800U, data);
256-
}
257251
static Uint8 slow_devices_reader ( const Uint32 addr32 ) {
258252
return cart_read_byte(addr32 - 0x4000000U);
259253
}
@@ -514,8 +508,8 @@ static void resolve_linear_slot ( const Uint32 slot, const Uint32 addr )
514508
}
515509
break;
516510
case MEM_SLOT_TYPE_ETH_BUFFER:
517-
mem_slot_rd_func[slot] = eth_buffer_reader;
518-
mem_slot_wr_func[slot] = eth_buffer_writer;
511+
mem_slot_rd_func[slot] = eth65_buffer_reader; // from ethernet65.h
512+
mem_slot_wr_func[slot] = eth65_buffer_writer; // -- "" --
519513
break;
520514
case MEM_SLOT_TYPE_OPL3:
521515
mem_slot_rd_func[slot] = dummy_reader; // TODO: what should I do here?

0 commit comments

Comments
 (0)