diff --git a/core/core.mk b/core/core.mk
index c0840baa1..3b3b83bd8 100755
--- a/core/core.mk
+++ b/core/core.mk
@@ -6,7 +6,7 @@
RZDCY_SRC_DIR ?= $(call my-dir)
-RZDCY_MODULES := cfg/ hw/arm7/ hw/aica/ hw/holly/ hw/ hw/gdrom/ hw/maple/ \
+RZDCY_MODULES := cfg/ hw/arm7/ hw/aica/ hw/holly/ hw/ hw/gdrom/ hw/maple/ hw/modem/ \
hw/mem/ hw/pvr/ hw/sh4/ hw/sh4/interpr/ hw/sh4/modules/ plugins/ profiler/ oslib/ \
hw/extdev/ hw/arm/ hw/naomi/ imgread/ linux/ ./ deps/coreio/ deps/zlib/ deps/chdr/ deps/crypto/ \
deps/libelf/ deps/chdpsr/ arm_emitter/ rend/ reios/ deps/libpng/ deps/xbrz/
diff --git a/core/hw/holly/sb_mem.cpp b/core/hw/holly/sb_mem.cpp
index 47b501fb9..8e83e71e6 100644
--- a/core/hw/holly/sb_mem.cpp
+++ b/core/hw/holly/sb_mem.cpp
@@ -13,6 +13,7 @@
#include "hw/gdrom/gdrom_if.h"
#include "hw/aica/aica_if.h"
#include "hw/naomi/naomi.h"
+#include "hw/modem/modem.h"
#include "hw/flashrom/flashrom.h"
#include "reios/reios.h"
@@ -150,7 +151,6 @@ T DYNACALL ReadMem_area0(u32 addr)
}
else if ((addr>= 0x005F7000) && (addr<= 0x005F70FF)) // GD-ROM
{
- //EMUERROR3("Read from area0_32 not implemented [GD-ROM], addr=%x,size=%d",addr,sz);
#if DC_PLATFORM == DC_PLATFORM_NAOMI
return (T)ReadMem_naomi(addr,sz);
#else
@@ -159,12 +159,10 @@ T DYNACALL ReadMem_area0(u32 addr)
}
else if (likely((addr>= 0x005F6800) && (addr<=0x005F7CFF))) // /*:PVR i/f Control Reg.*/ -> ALL SB registers now
{
- //EMUERROR2("Read from area0_32 not implemented [PVR i/f Control Reg], addr=%x",addr);
return (T)sb_ReadMem(addr,sz);
}
else if (likely((addr>= 0x005F8000) && (addr<=0x005F9FFF))) // :TA / PVR Core Reg.
{
- //EMUERROR2("Read from area0_32 not implemented [TA / PVR Core Reg], addr=%x",addr);
verify(sz==4);
return (T)pvr_ReadReg(addr);
}
@@ -172,8 +170,11 @@ T DYNACALL ReadMem_area0(u32 addr)
//map 0x0060 to 0x0060
else if ((base ==0x0060) /*&& (addr>= 0x00600000)*/ && (addr<= 0x006007FF)) // :MODEM
{
- return (T)libExtDevice_ReadMem_A0_006(addr,sz);
- //EMUERROR2("Read from area0_32 not implemented [MODEM], addr=%x",addr);
+#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
+ return (T)libExtDevice_ReadMem_A0_006(addr, sz);
+#else
+ return (T)ModemReadMem_A0_006(addr, sz);
+#endif
}
//map 0x0060 to 0x006F
else if ((base >=0x0060) && (base <=0x006F) && (addr>= 0x00600800) && (addr<= 0x006FFFFF)) // :G2 (Reserved)
@@ -183,26 +184,21 @@ T DYNACALL ReadMem_area0(u32 addr)
//map 0x0070 to 0x0070
else if ((base ==0x0070) /*&& (addr>= 0x00700000)*/ && (addr<=0x00707FFF)) // :AICA- Sound Cntr. Reg.
{
- //EMUERROR2("Read from area0_32 not implemented [AICA- Sound Cntr. Reg], addr=%x",addr);
return (T) ReadMem_aica_reg(addr,sz);//libAICA_ReadReg(addr,sz);
}
//map 0x0071 to 0x0071
else if ((base ==0x0071) /*&& (addr>= 0x00710000)*/ && (addr<= 0x0071000B)) // :AICA- RTC Cntr. Reg.
{
- //EMUERROR2("Read from area0_32 not implemented [AICA- RTC Cntr. Reg], addr=%x",addr);
return (T)ReadMem_aica_rtc(addr,sz);
}
//map 0x0080 to 0x00FF
else if ((base >=0x0080) && (base <=0x00FF) /*&& (addr>= 0x00800000) && (addr<=0x00FFFFFF)*/) // :AICA- Wave Memory
{
- //EMUERROR2("Read from area0_32 not implemented [AICA- Wave Memory], addr=%x",addr);
- //return (T)libAICA_ReadMem_aica_ram(addr,sz);
ReadMemArrRet(aica_ram.data,addr&ARAM_MASK,sz);
}
//map 0x0100 to 0x01FF
else if ((base >=0x0100) && (base <=0x01FF) /*&& (addr>= 0x01000000) && (addr<= 0x01FFFFFF)*/) // :Ext. Device
{
- // EMUERROR2("Read from area0_32 not implemented [Ext. Device], addr=%x",addr);
return (T)libExtDevice_ReadMem_A0_010(addr,sz);
}
return 0;
@@ -218,13 +214,11 @@ void DYNACALL WriteMem_area0(u32 addr,T data)
//map 0x0000 to 0x001F
if ((base <=0x001F) /*&& (addr<=0x001FFFFF)*/)// :MPX System/Boot ROM
{
- //EMUERROR4("Write to [MPX System/Boot ROM] is not possible, addr=%x,data=%x,size=%d",addr,data,sz);
WriteBios(addr,data,sz);
}
//map 0x0020 to 0x0021
else if ((base >=0x0020) && (base <=0x0021) /*&& (addr>= 0x00200000) && (addr<= 0x0021FFFF)*/) // Flash Memory
{
- //EMUERROR4("Write to [Flash Memory] , sz?!, addr=%x,data=%x,size=%d",addr,data,sz);
WriteFlash(addr,data,sz);
}
//map 0x0040 to 0x005F -> actually, I'll only map 0x005F to 0x005F, b/c the rest of it is unspammed (left to default handler)
@@ -237,7 +231,6 @@ void DYNACALL WriteMem_area0(u32 addr,T data)
}
else if ((addr>= 0x005F7000) && (addr<= 0x005F70FF)) // GD-ROM
{
- //EMUERROR4("Write to area0_32 not implemented [GD-ROM], addr=%x,data=%x,size=%d",addr,data,sz);
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
WriteMem_naomi(addr,data,sz);
#else
@@ -246,12 +239,10 @@ void DYNACALL WriteMem_area0(u32 addr,T data)
}
else if ( likely((addr>= 0x005F6800) && (addr<=0x005F7CFF)) ) // /*:PVR i/f Control Reg.*/ -> ALL SB registers
{
- //EMUERROR4("Write to area0_32 not implemented [PVR i/f Control Reg], addr=%x,data=%x,size=%d",addr,data,sz);
sb_WriteMem(addr,data,sz);
}
else if ( likely((addr>= 0x005F8000) && (addr<=0x005F9FFF)) ) // TA / PVR Core Reg.
{
- //EMUERROR4("Write to area0_32 not implemented [TA / PVR Core Reg], addr=%x,data=%x,size=%d",addr,data,sz);
verify(sz==4);
pvr_WriteReg(addr,data);
}
@@ -259,8 +250,11 @@ void DYNACALL WriteMem_area0(u32 addr,T data)
//map 0x0060 to 0x0060
else if ((base ==0x0060) /*&& (addr>= 0x00600000)*/ && (addr<= 0x006007FF)) // MODEM
{
- //EMUERROR4("Write to area0_32 not implemented [MODEM], addr=%x,data=%x,size=%d",addr,data,sz);
- libExtDevice_WriteMem_A0_006(addr,data,sz);
+#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
+ libExtDevice_WriteMem_A0_006(addr, data, sz);
+#else
+ ModemWriteMem_A0_006(addr, data, sz);
+#endif
}
//map 0x0060 to 0x006F
else if ((base >=0x0060) && (base <=0x006F) && (addr>= 0x00600800) && (addr<= 0x006FFFFF)) // G2 (Reserved)
@@ -270,29 +264,24 @@ void DYNACALL WriteMem_area0(u32 addr,T data)
//map 0x0070 to 0x0070
else if ((base >=0x0070) && (base <=0x0070) /*&& (addr>= 0x00700000)*/ && (addr<=0x00707FFF)) // AICA- Sound Cntr. Reg.
{
- //EMUERROR4("Write to area0_32 not implemented [AICA- Sound Cntr. Reg], addr=%x,data=%x,size=%d",addr,data,sz);
WriteMem_aica_reg(addr,data,sz);
return;
}
//map 0x0071 to 0x0071
else if ((base >=0x0071) && (base <=0x0071) /*&& (addr>= 0x00710000)*/ && (addr<= 0x0071000B)) // AICA- RTC Cntr. Reg.
{
- //EMUERROR4("Write to area0_32 not implemented [AICA- RTC Cntr. Reg], addr=%x,data=%x,size=%d",addr,data,sz);
WriteMem_aica_rtc(addr,data,sz);
return;
}
//map 0x0080 to 0x00FF
else if ((base >=0x0080) && (base <=0x00FF) /*&& (addr>= 0x00800000) && (addr<=0x00FFFFFF)*/) // AICA- Wave Memory
{
- //EMUERROR4("Write to area0_32 not implemented [AICA- Wave Memory], addr=%x,data=%x,size=%d",addr,data,sz);
- //aica_writeram(addr,data,sz);
WriteMemArrRet(aica_ram.data,addr&ARAM_MASK,data,sz);
return;
}
//map 0x0100 to 0x01FF
else if ((base >=0x0100) && (base <=0x01FF) /*&& (addr>= 0x01000000) && (addr<= 0x01FFFFFF)*/) // Ext. Device
{
- //EMUERROR4("Write to area0_32 not implemented [Ext. Device], addr=%x,data=%x,size=%d",addr,data,sz);
libExtDevice_WriteMem_A0_010(addr,data,sz);
}
return;
diff --git a/core/hw/modem/modem.cpp b/core/hw/modem/modem.cpp
new file mode 100644
index 000000000..a2d03e1eb
--- /dev/null
+++ b/core/hw/modem/modem.cpp
@@ -0,0 +1,737 @@
+/*
+ Originally based on nullDC: nullExtDev/modem.cpp
+
+ Created on: Sep 9, 2018
+
+ Copyright 2018 skmp, flyinghead
+
+ This file is part of reicast.
+
+ reicast is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ reicast is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with reicast. If not, see .
+ */
+
+#include "modem.h"
+#include "modem_regs.h"
+#include "hw/holly/holly_intc.h"
+#include "hw/sh4/sh4_sched.h"
+#include "oslib/oslib.h"
+#include "pppd.h"
+
+#define MODEM_COUNTRY_RES 0
+#define MODEM_COUNTRY_JAP 1
+#define MODEM_COUNTRY_USA 2
+
+#define MODEM_MAKER_SEGA 0
+#define MODEM_MAKER_ROCKWELL 1
+
+#define MODEM_DEVICE_TYPE_336K 0
+
+#ifdef RELEASE
+#define LOG(...)
+#else
+#define LOG(...) do { printf("[%d.%03d] MODEM ", (int)os_GetSeconds(), (int)(os_GetSeconds() * 1000) % 1000); printf(__VA_ARGS__); putchar('\n'); } while (false);
+#endif
+
+const static u32 MODEM_ID[2] =
+{
+ MODEM_COUNTRY_RES,
+ (MODEM_MAKER_ROCKWELL<<4) | (MODEM_DEVICE_TYPE_336K),
+};
+
+static modemreg_t modem_regs;
+
+static u8 dspram[0x1000];
+
+static int modem_sched;
+
+enum ModemStates
+{
+ MS_INVALID, //needs reset
+ MS_RESET, //reset is low
+ MS_RESETING, //reset is hi
+ MS_ST_CONTROLER, //Controller self test
+ MS_ST_DSP, //DSP self test
+ MS_END_DSP, //DSP self test end
+ MS_NORMAL, //Normal operation
+
+};
+static ModemStates state = MS_INVALID;
+
+enum ConnectState
+{
+ DISCONNECTED,
+ DIALING,
+ RINGING,
+ HANDSHAKING,
+ CONNECTED,
+};
+static ConnectState connect_state = DISCONNECTED;
+
+static void schedule_callback(int ms);
+
+static void update_interrupt()
+{
+ modem_regs.reg1e.RDBIA = modem_regs.reg1e.RDBIE && modem_regs.reg1e.RDBF;
+ modem_regs.reg1e.TDBIA = modem_regs.reg1e.TDBIE && modem_regs.reg1e.TDBE;
+
+ if (modem_regs.reg1f.NCIA || modem_regs.reg1f.NSIA || modem_regs.reg1e.RDBIA || modem_regs.reg1e.TDBIA)
+ asic_RaiseInterrupt(holly_EXP_8BIT);
+ else
+ asic_CancelInterrupt(holly_EXP_8BIT);
+}
+
+static u32 get_masked_status(u32 reg)
+{
+ u8 int_mask = dspram[regs_int_mask_addr[reg]];
+ return int_mask & modem_regs.ptr[reg];
+}
+
+#define SET_STATUS_BIT(reg, bit, value) do { \
+ if ((bit) != (value)) \
+ { \
+ if (!modem_regs.reg1f.NSIE) \
+ { \
+ bit = (value); \
+ } \
+ else \
+ { \
+ u8 before = get_masked_status(reg); \
+ bit = (value); \
+ if (before != get_masked_status(reg)) \
+ modem_regs.reg1f.NSIA = 1; \
+ } \
+ } \
+} while (false);
+
+static void ControllerTestEnd();
+static void DSPTestStart();
+static void DSPTestEnd();
+
+static double last_dial_time;
+
+#ifndef RELEASE
+static double last_comm_stats;
+static int sent_bytes;
+static int recvd_bytes;
+static FILE *recv_fp;
+static FILE *sent_fp;
+#endif
+
+static int modem_sched_func(int tag, int c, int j)
+{
+#ifndef RELEASE
+ if (os_GetSeconds() - last_comm_stats >= 2)
+ {
+ if (last_comm_stats != 0)
+ {
+ printf("Stats sent %d received %d TDBE %d RDBF %d\n", sent_bytes, recvd_bytes, modem_regs.reg1e.TDBE, modem_regs.reg1e.RDBF);
+ sent_bytes = 0;
+ recvd_bytes = 0;
+ }
+ last_comm_stats = os_GetSeconds();
+ }
+#endif
+ switch (state)
+ {
+ case MS_ST_CONTROLER:
+ ControllerTestEnd();
+ break;
+ case MS_ST_DSP:
+ DSPTestStart();
+ break;
+ case MS_END_DSP:
+ DSPTestEnd();
+ break;
+ case MS_NORMAL:
+ modem_regs.reg1f.NEWC = 0; // Not needed when state is CONNECTED but who cares
+
+ switch (connect_state)
+ {
+ case DIALING:
+ if (last_dial_time != 0 && os_GetSeconds() - last_dial_time > 0.99)
+ {
+ LOG("Switching to RINGING state");
+ connect_state = RINGING;
+ schedule_callback(100);
+ }
+ else
+ {
+ last_dial_time = os_GetSeconds();
+
+ modem_regs.reg1e.TDBE = 1;
+ schedule_callback(1000); // To switch to Ringing state
+ }
+ break;
+ case RINGING:
+ last_dial_time = 0;
+ LOG("\t\t *** RINGING STATE ***");
+ modem_regs.reg1f.NEWS = 1;
+ if (!modem_regs.reg09.DATA)
+ {
+ SET_STATUS_BIT(0x0f, modem_regs.reg0f.RI, 1);
+ SET_STATUS_BIT(0x0b, modem_regs.reg0b.ATV25, 1);
+ SET_STATUS_BIT(0x0b, modem_regs.reg0b.ATBEL, 1);
+ }
+ if (modem_regs.reg12 == 0xAA)
+ {
+ // V8 AUTO mode
+ dspram[0x302] |= 1 << 3; // Detect ANSam
+ }
+ break;
+ case HANDSHAKING:
+ LOG("\t\t *** HANDSHAKING STATE ***");
+ if (modem_regs.reg03.RLSDE)
+ SET_STATUS_BIT(0x0f, modem_regs.reg0f.RLSD, 1);
+ if (modem_regs.reg1f.NSIE)
+ {
+ // CONF
+ if (dspram[regs_int_mask_addr[0x12]] & (1 << 7))
+ modem_regs.reg1f.NSIA = 1;
+ // SPEED
+ if (dspram[regs_int_mask_addr[0x0e]] & 0x1f)
+ modem_regs.reg1f.NSIA = 1;
+ // ABCODE
+ if (dspram[regs_int_mask_addr[0x014]])
+ modem_regs.reg1f.NSIA = 1;
+ }
+ if (modem_regs.reg08.ASYN)
+ {
+ modem_regs.reg12 = 0xce; // CONF V34 - K56flex
+ modem_regs.reg0e.SPEED = 0x10; // 33.6k
+ }
+ else
+ {
+ // Force the driver to ASYN=1 so it sends raw data
+ modem_regs.reg12 = 0xa4; // CONF V23
+ modem_regs.reg0e.SPEED = 0x02; // 1.2k
+ //modem_regs.reg0e.SPEED = 0x10; // 33.6k. Obviously wrong for V23 but may help some games complaining about low quality link
+ }
+ modem_regs.reg14 = 0x00; // ABCODE: no error
+ modem_regs.reg1f.NEWS = 1;
+ SET_STATUS_BIT(0x0f, modem_regs.reg0f.RI, 0);
+ SET_STATUS_BIT(0x0b, modem_regs.reg0b.ATV25, 0);
+ SET_STATUS_BIT(0x0b, modem_regs.reg0b.ATBEL, 0);
+ SET_STATUS_BIT(0x0f, modem_regs.reg0f.DSR, 1);
+ if (modem_regs.reg02.v0.V54PE)
+ SET_STATUS_BIT(0x0f, modem_regs.reg0f.V54DT, 1);
+ if (modem_regs.reg02.v0.RTSDE)
+ SET_STATUS_BIT(0x0f, modem_regs.reg0f.RTSDT, 1);
+
+ // What is this? This is required for games to detect the connection
+ // Can be set now or at connected state
+ SET_STATUS_BIT(0x0f, modem_regs.reg0f.FED, 1);
+
+ start_pppd();
+ break;
+
+ case CONNECTED:
+#ifndef RELEASE
+ static bool mem_dumped;
+ if (!mem_dumped)
+ {
+ mem_dumped = true;
+ for (int i = 0 ; i < sizeof(modem_regs); i++)
+ LOG("modem_regs %02x == %02x", i, modem_regs.ptr[i]);
+ }
+#endif
+ if (!modem_regs.reg1e.RDBF)
+ {
+ int c = read_pppd();
+ if (c >= 0)
+ {
+ //LOG("pppd received %02x", c);
+#ifndef RELEASE
+ recvd_bytes++;
+#endif
+ modem_regs.reg00 = c & 0xFF;
+ modem_regs.reg1e.RDBF = 1;
+ if (modem_regs.reg04.FIFOEN)
+ SET_STATUS_BIT(0x0c, modem_regs.reg0c.RXFNE, 1);
+ }
+ }
+ modem_regs.reg1e.TDBE = 1;
+ }
+ break;
+ }
+ update_interrupt();
+
+ if (connect_state == HANDSHAKING)
+ {
+ connect_state = CONNECTED;
+ return SH4_MAIN_CLOCK / 1000 * 500; // 500 ms
+ }
+ return connect_state == CONNECTED ? (SH4_MAIN_CLOCK / 1000000 * 238) : 0; // 238us
+}
+
+static void schedule_callback(int ms)
+{
+ if (modem_sched == 0)
+ modem_sched = sh4_sched_register(0, &modem_sched_func);
+ sh4_sched_request(modem_sched, SH4_MAIN_CLOCK / 1000 * ms);
+}
+
+#define SetReg16(rh,rl,v) {modem_regs.ptr[rh]=(v)>>8;modem_regs.ptr[rl]=(v)&0xFF; }
+
+static void NormalDefaultRegs()
+{
+ verify(state == MS_NORMAL);
+ verify(sizeof(regs_write_mask) == sizeof(modem_regs));
+ verify(sizeof(por_dspram) == sizeof(dspram));
+
+ // Default values for normal state
+ memset(&modem_regs, 0, sizeof(modem_regs));
+ memcpy(dspram, por_dspram, sizeof(dspram));
+ modem_regs.reg05.CEQ = 1;
+ modem_regs.reg12 = 0x76; // CONF: V.32 bis TCM 14400
+ modem_regs.reg09.DATA = 1;
+ modem_regs.reg09.DTMF = 1;
+ modem_regs.reg15.HWRWK = 1;
+ modem_regs.reg07.RDLE = 1;
+ modem_regs.reg15.RDWK = 1;
+ modem_regs.reg03.RLSDE = 1;
+ modem_regs.reg02.TDE = 1;
+ modem_regs.reg13.TLVL = 0x9;
+
+ modem_regs.reg1e.TDBE = 1;
+ connect_state = DISCONNECTED;
+ last_dial_time = 0;
+}
+static void DSPTestEnd()
+{
+ verify(state==MS_END_DSP);
+ state=MS_NORMAL;
+
+ LOG("DSPTestEnd");
+ NormalDefaultRegs();
+}
+static void DSPTestStart()
+{
+ verify(state==MS_ST_DSP);
+ state=MS_END_DSP;
+ LOG("DSPTestStart");
+
+ modem_regs.reg1e.TDBE = 1;
+ SetReg16(0x1B,0x1A,0xF083); // EC checksum
+ SetReg16(0x19,0x18,0x46EE); // Multiplier checksum
+ SetReg16(0x17,0x16,0x00FA); // RAM checksum
+ SetReg16(0x15,0x14,0x0A09); // ROM checksum
+ SetReg16(0x13,0x12,0x3730); // Part number
+ SetReg16(0x11,0x00,0x2041); // Revision level
+
+ schedule_callback(50);
+}
+static void ControllerTestEnd()
+{
+ verify(state==MS_ST_CONTROLER);
+ state=MS_ST_DSP;
+
+ schedule_callback(50);
+}
+
+//End the reset and start internal tests
+static void ControllerTestStart()
+{
+ verify(state==MS_RESETING);
+ //Set Self test values :)
+ state=MS_ST_CONTROLER;
+ //k, lets set values
+
+ //1E:3 -> set
+ modem_regs.reg1e.TDBE=1;
+
+/*
+ RAM1 Checksum = 0xEA3C or 0x451
+ RAM2 Checksum = 0x5536 or 0x49A5
+ ROM1 Checksum = 0x5F4C
+ ROM2 Checksum = 0x3835 or 0x3836
+ Timer/ROM/RAM = 0x801 or 0xDE00
+ Part Number = 0x3730 or 0x3731
+ Revision Level = 0x4241
+*/
+ SetReg16(0x1D,0x1C,0xEA3C);
+ SetReg16(0x1B,0x1A,0x5536);
+ SetReg16(0x19,0x18,0x5F4C);
+ SetReg16(0x17,0x16,0x3835);
+ SetReg16(0x15,0x14,0x801);
+ SetReg16(0x13,0x12,0x3730);
+ SetReg16(0x11,0x0,0x4241);
+
+ ControllerTestEnd();
+}
+
+static void modem_reset(u32 v)
+{
+ if (v==0)
+ {
+ memset(&modem_regs,0,sizeof(modem_regs));
+ state=MS_RESET;
+ LOG("Modem reset start ...");
+ }
+ else
+ {
+ stop_pppd();
+ memset(&modem_regs,0,sizeof(modem_regs));
+ state=MS_RESETING;
+ modem_regs.ptr[0x20]=1;
+ ControllerTestStart();
+ LOG("Modem reset end ...");
+ }
+}
+
+static void check_start_handshake()
+{
+ if (modem_regs.reg09.DTR
+ && (modem_regs.reg09.DATA || modem_regs.reg15.AUTO)
+ && connect_state == RINGING)
+ {
+ LOG("DTR asserted. starting handshaking");
+ connect_state = HANDSHAKING;
+ schedule_callback(1000);
+ }
+}
+
+static bool word_dspram_write;
+static bool module_download;
+static u32 reg1b_save;
+static u8 download_crc;
+
+static void ModemNormalWrite(u32 reg, u32 data)
+{
+#ifndef RELEASE
+ if (recv_fp == NULL)
+ {
+ recv_fp = fopen("ppp_recv.dump", "w");
+ sent_fp = fopen("ppp_sent.dump", "w");
+ }
+#endif
+ //if (!module_download && reg != 0x10)
+ // LOG("ModemNormalWrite : %03X=%X", reg,data);
+ u32 old = modem_regs.ptr[reg];
+ modem_regs.ptr[reg] = (old & ~regs_write_mask[reg]) | (data & regs_write_mask[reg]);
+
+ switch(reg)
+ {
+ case 0x02:
+ if (modem_regs.reg02.v0.V54PE)
+ LOG("V54PE set");
+ if (modem_regs.reg02.v0.V54AE)
+ LOG("V54AE set");
+ if (modem_regs.reg02.v0.V54TE)
+ LOG("V54TE set");
+ modem_regs.reg0f.RTSDT = modem_regs.reg02.v0.RTSDE & connect_state == CONNECTED;
+ break;
+
+ case 0x06:
+ LOG("PEN = %d", modem_regs.reg06.PEN);
+ if (modem_regs.reg06.PEN)
+ die("PEN = 1");
+ if (modem_regs.reg06.HDLC)
+ die("HDLC = 1");
+ break;
+
+ case 0x08:
+ LOG("TPDM = %d ASYN = %d", modem_regs.reg08.TPDM, modem_regs.reg08.ASYN);
+ break;
+
+ case 0x09:
+ check_start_handshake(); // DTR and DATA
+ break;
+
+ case 0x10: // TBUFFER
+ //LOG("ModemNormalWrite : TBUFFER = %X", data);
+ if (module_download)
+ {
+ download_crc = (download_crc << 1) + ((download_crc & 0x80) >> 7) + (data & 0xFF);
+ }
+ else if (connect_state == DISCONNECTED || connect_state == DIALING)
+ {
+ if (connect_state == DISCONNECTED)
+ {
+ LOG("Switching to DIALING...");
+ connect_state = DIALING;
+ }
+ schedule_callback(100);
+ }
+ else if (connect_state == CONNECTED && modem_regs.reg08.RTS)
+ {
+ //LOG("pppd write %02x", data);
+#ifndef RELEASE
+ sent_bytes++;
+ if (sent_fp)
+ fputc(data, sent_fp);
+#endif
+ write_pppd(data);
+ if (!modem_regs.reg08.ASYN || modem_regs.reg12 == 0xa4) // CONF = V23
+ // Wait for the next schedule before setting the TX empty flag?
+ modem_regs.reg1e.TDBE = 0;
+ else
+ modem_regs.reg1e.TDBE = 1;
+ }
+ break;
+
+ case 0x11:
+ LOG("PARSL = %d", modem_regs.reg11.PARSL);
+ die("PARSL");
+ break;
+
+ case 0x14: // ABCODE
+ if (data == 0x4f || data == 0x5f)
+ {
+ reg1b_save = modem_regs.ptr[0x1b];
+ modem_regs.ptr[0x1b] = data;
+ //LOG("SPX/CTL download initiated");
+ module_download = true;
+ download_crc = 0;
+ }
+ else if (data == 0 && module_download)
+ {
+ // If module download is in progress, this signals the end of it
+ modem_regs.reg17 = 0xFF;
+ modem_regs.reg16 = download_crc;
+ // Restore reg 1b
+ modem_regs.ptr[0x1b] = reg1b_save;
+ module_download = false;
+ //LOG("SPX/CTL download finished CRC %02x", download_crc);
+ }
+ break;
+
+ case 0x15:
+ check_start_handshake(); // AUTO
+ break;
+
+ //Data Write Regs, for transfers to DSP
+ case 0x18: // MEDAL
+ break;
+
+ case 0x19: // MEDAM
+ word_dspram_write = true;
+ break;
+
+ case 0x1a:
+ verify(connect_state != CONNECTED || !modem_regs.reg1a.SCIBE);
+ break;
+
+ //Address low
+ case 0x1C: // MEADDL
+ break;
+
+ case 0x1D: // MEADDH
+ if (modem_regs.reg1c_1d.MEMW && !(old & 1 << 13))
+ {
+ word_dspram_write = false;
+ }
+ if (modem_regs.reg1c_1d.MEACC)
+ {
+ modem_regs.reg1c_1d.MEACC=0;
+ modem_regs.reg1f.NEWS = 1;
+ u32 dspram_addr = modem_regs.reg1c_1d.MEMADD_l | (modem_regs.reg1c_1d.MEMADD_h << 8);
+ if (modem_regs.reg1c_1d.MEMW)
+ {
+ //LOG("DSP mem Write%s address %08x = %x",
+ // word_dspram_write ? " (w)" : "",
+ // dspram_addr,
+ // modem_regs.reg18_19 );
+ if (word_dspram_write)
+ {
+ if (dspram_addr & 1)
+ {
+ dspram[dspram_addr] = modem_regs.reg18_19 & 0xFF;
+ dspram[dspram_addr + 1] = (modem_regs.reg18_19 >> 8) & 0xFF;
+ }
+ else
+ *(u16*)&dspram[dspram_addr] = modem_regs.reg18_19;
+ }
+ else
+ dspram[dspram_addr] = modem_regs.reg18_19 & 0xFF;
+ }
+ else
+ {
+ if (dspram_addr & 1)
+ modem_regs.reg18_19 = dspram[dspram_addr] | (dspram[dspram_addr + 1] << 8);
+ else
+ modem_regs.reg18_19 = *(u16*)&dspram[dspram_addr];
+ //LOG("DSP mem Read address %08x == %x",
+ // dspram_addr,
+ // modem_regs.reg18_19 );
+ }
+ }
+ break;
+
+ case 0x1F:
+ if (!modem_regs.reg1f.NCIE)
+ modem_regs.reg1f.NCIA = 0;
+ if (modem_regs.reg1f.NEWC)
+ {
+ if(modem_regs.reg1a.SFRES)
+ {
+ modem_regs.reg1a.SFRES = 0;
+ LOG("Soft Reset SET && NEWC, executing reset and init");
+ modem_reset(1);
+ }
+ else
+ {
+ modem_regs.reg1f.NEWC = 0; // accept the settings
+ if (modem_regs.reg1f.NCIE)
+ modem_regs.reg1f.NCIA = 1;
+ LOG("NEWC CONF=%x", modem_regs.reg12);
+ }
+ }
+ // Don't allow NEWS to be set if 0
+ if (old & (1 << 3) == 0)
+ modem_regs.reg1f.NEWS = 0;
+ if (!modem_regs.reg1f.NEWS)
+ {
+ modem_regs.reg1f.NSIA = 0;
+ }
+ break;
+
+ default:
+ //printf("ModemNormalWrite : undef %03X=%X\n",reg,data);
+ break;
+ }
+ update_interrupt();
+}
+
+u32 ModemReadMem_A0_006(u32 addr, u32 size)
+{
+ u32 reg=addr&0x7FF;
+ verify((reg&3)==0);
+ reg>>=2;
+
+ if (reg<0x100)
+ {
+ verify(reg<=1);
+ LOG("Reading MODEM ID addr %03x", reg);
+ return MODEM_ID[reg];
+ }
+ else
+ {
+ reg-=0x100;
+ if (reg<0x21)
+ {
+ if (state==MS_NORMAL)
+ {
+ // Dial tone is detected if TONEA, TONEB and TONEC are set
+ //if (reg==0xF)
+ {
+ SET_STATUS_BIT(0x0f, modem_regs.reg0f.CTS, modem_regs.reg08.RTS && connect_state == CONNECTED);
+ SET_STATUS_BIT(0x0b, modem_regs.reg0b.TONEA, connect_state == DISCONNECTED);
+ SET_STATUS_BIT(0x0b, modem_regs.reg0b.TONEB, connect_state == DISCONNECTED);
+ SET_STATUS_BIT(0x0b, modem_regs.reg0b.TONEC, connect_state == DISCONNECTED);
+ // FIXME This should be reset if transmit buffer is full
+ if (modem_regs.reg04.FIFOEN || module_download)
+ SET_STATUS_BIT(0x0d, modem_regs.reg0d.TXFNF, 1);
+ }
+ //LOG("Read reg %03x == %x", reg, modem_regs.ptr[reg]);
+ u8 data = modem_regs.ptr[reg];
+ if (reg == 0x00) // RBUFFER
+ {
+ //LOG("Read RBUFFER = %X", data);
+ modem_regs.reg1e.RDBF = 0;
+ SET_STATUS_BIT(0x0c, modem_regs.reg0c.RXFNE, 0);
+ if (connect_state == CONNECTED)
+ {
+#ifndef RELEASE
+ if (recv_fp)
+ fputc(data, recv_fp);
+#endif
+ // FIXME Code dup with sched_func
+ int c = read_pppd();
+ if (c >= 0)
+ {
+ //LOG("pppd received %02x", c);
+#ifndef RELEASE
+ recvd_bytes++;
+#endif
+ modem_regs.reg00 = c & 0xFF;
+ modem_regs.reg1e.RDBF = 1;
+ if (modem_regs.reg04.FIFOEN)
+ SET_STATUS_BIT(0x0c, modem_regs.reg0c.RXFNE, 1);
+ }
+ }
+ update_interrupt();
+ }
+ return data;
+ }
+ else if (state==MS_ST_CONTROLER || state==MS_ST_DSP)
+ {
+ if (reg==0x10)
+ {
+ modem_regs.reg1e.TDBE=0;
+ return 0;
+ }
+ else
+ {
+ //printf("modem reg %03X read -- reset/test state\n",reg);
+ return modem_regs.ptr[reg];
+ }
+ }
+ else if (state==MS_RESETING)
+ {
+ return 0; //still reset
+ }
+ else
+ {
+ LOG("Read (reset) reg %03x == %x", reg, modem_regs.ptr[reg]);
+ return modem_regs.ptr[reg];
+ }
+ }
+ else
+ {
+ LOG("modem reg %03X read -- wtf is it ?",reg);
+ return 0;
+ }
+ }
+}
+
+void ModemWriteMem_A0_006(u32 addr, u32 data, u32 size)
+{
+ u32 reg=addr&0x7FF;
+ verify((reg&3)==0);
+ reg>>=2;
+
+
+
+ if (reg<0x100)
+ {
+ verify(reg<=1);
+ LOG("modem reg %03X write -- MODEM ID?!",reg);
+ }
+ else
+ {
+ reg-=0x100;
+ if (reg<0x20)
+ {
+ if (state==MS_NORMAL)
+ {
+ ModemNormalWrite(reg,data);
+ }
+ else
+ {
+ LOG("modem reg %03X write %X -- undef state?",reg,data);
+ }
+ return;
+ }
+ else if (reg==0x20)
+ {
+ //Hard reset
+ modem_reset(data);
+ }
+ else
+ {
+ LOG("modem reg %03X write %X -- wtf is it?",reg,data);
+ return;
+ }
+ }
+}
diff --git a/core/hw/modem/modem.h b/core/hw/modem/modem.h
new file mode 100644
index 000000000..2b9c5460f
--- /dev/null
+++ b/core/hw/modem/modem.h
@@ -0,0 +1,28 @@
+/*
+ Originally based on nullDC: nullExtDev/modem.h
+
+ Created on: Sep 9, 2018
+
+ Copyright 2018 skmp, flyinghead
+
+ This file is part of reicast.
+
+ reicast is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ reicast is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with reicast. If not, see .
+ */
+
+#pragma once
+#include "types.h"
+
+u32 ModemReadMem_A0_006(u32 addr,u32 size);
+void ModemWriteMem_A0_006(u32 addr,u32 data,u32 size);
diff --git a/core/hw/modem/modem_regs.h b/core/hw/modem/modem_regs.h
new file mode 100644
index 000000000..2c013e65c
--- /dev/null
+++ b/core/hw/modem/modem_regs.h
@@ -0,0 +1,698 @@
+/*
+ Originally based on nullDC: nullExtDev/modem.cpp
+
+ Created on: Sep 9, 2018
+
+ Copyright 2018 skmp, flyinghead
+
+ This file is part of reicast.
+
+ reicast is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ reicast is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with reicast. If not, see .
+ */
+#pragma once
+
+#pragma pack(1)
+union modemreg_t
+{
+ u8 ptr[0x21];
+ struct
+ {
+ //00 Receive Data Buffer (RBUFFER)/Voice Receive Data Buffer (VBUFR)
+ u8 reg00;
+ //01 VOLUME VPAUSE - - TXHF RXHF RXP
+ struct
+ {
+ u8 RXP:1;
+ u8 RXHF:1;
+ u8 TXHF:1;
+ u8 nil2:2;
+ u8 VPAUSE:1;
+ u8 VOLUME:2;
+ } reg01;
+ //02 TDE SQDIS S511 - RTSDE V54TE V54AE V54PE
+ // DCDEN CDEN - - CODBITS
+ struct
+ {
+ union
+ {
+ struct
+ {
+ u8 V54PE:1;
+ u8 V54AE:1;
+ u8 V54TE:1;
+ u8 RTSDE:1;
+ u8 nil1:1;
+ u8 S511:1;
+ } v0;
+ struct
+ {
+ u8 CODBITS:2;
+ u8 nil2:2;
+ u8 CDEN:1;
+ u8 DCDEN:1;
+ } v1;
+ struct
+ {
+ u8 nila:6;
+ u8 TDE:1;
+ u8 SQDIS:1;
+ };
+ };
+ } reg02;
+ //03 EPT SEPT SRCEN RLSDE - - GTE GTS
+ struct
+ {
+ u8 GTS:1;
+ u8 GTE:1;
+ u8 nil2:2;
+ u8 RLSDE:1;
+ u8 SRCEN:1;
+ u8 SEPT:1;
+ u8 EPT:1;
+ } reg03;
+ //04 RB - - FIFOEN - NRZIEN/VAGC TOD STRN
+ struct
+ {
+ u8 STRN:1;
+ u8 TOD:1;
+ u8 NRZIEN_VAGC:1;
+ u8 nil1_1:1;
+ u8 FIFOEN:1;
+ u8 nil1:2;
+ u8 RB:1;
+ } reg04;
+ //05 - - - TXSQ CEQ - STOFF -
+ struct
+ {
+ u8 nil1_2:1;
+ u8 STOFF:1;
+ u8 nil1_1:1;
+ u8 CEQ:1;
+ u8 TXSQ:1;
+ u8 nil1:3;
+ } reg05;
+ //06 - EXOS - HDLC PEN STB WDSZ/DECBITS
+ struct
+ {
+ u8 WDSZ_DECBITS:2;
+ u8 STB:1;
+ u8 PEN:1;
+ u8 HDLC:1;
+ u8 nil1_1:1;
+ u8 EXOS:1;
+ u8 nil1:1;
+ } reg06;
+ //07 RDLE RDL L2ACT - L3ACT - RA MHLD
+ struct
+ {
+ u8 MHLD:1;
+ u8 RA:1;
+ u8 nil1_1:1;
+ u8 L3ACT:1;
+ u8 nil1:1;
+ u8 L2ACT:1;
+ u8 RDL:1;
+ u8 RDLE:1;
+ } reg07;
+ //08 ASYN TPDM V21S V54T V54A V54P RTRN RTS
+ struct
+ {
+ u8 RTS:1;
+ u8 RTRN:1;
+ u8 V54P:1;
+ u8 V54A:1;
+ u8 V54T:1;
+ u8 V21S:1;
+ u8 TPDM:1;
+ u8 ASYN:1;
+ } reg08;
+ //09 NV25 CC DTMF ORG LL DATA RRTSE DTR
+ struct
+ {
+ u8 DTR:1;
+ u8 RRTSE:1;
+ u8 DATA:1;
+ u8 LL:1;
+ u8 ORG:1;
+ u8 DTMF:1;
+ u8 CC:1;
+ u8 NV25:1;
+ } reg09;
+ //0A PNSUC FLAGDT PE FE OE CRCS FLAGS SYNCD
+ struct
+ {
+ u8 SYNCD:1;
+ u8 FLAGS:1;
+ u8 CRCS:1;
+ u8 OE:1;
+ u8 FE:1;
+ u8 PE:1;
+ u8 FLAGDT:1;
+ u8 PNSUC:1;
+ } reg0a;
+ //0B TONEA TONEB TONEC ATV25 ATBEL - DISDET EQMAT
+ struct
+ {
+ u8 EQMAT:1;
+ u8 DISDET:1;
+ u8 nil:1;
+ u8 ATBEL:1;
+ u8 ATV25:1;
+ u8 TONEC:1;
+ u8 TONEB:1;
+ u8 TONEA:1;
+ } reg0b;
+ //0C AADET ACDET CADET CCDET SDET SNDET RXFNE RSEQ
+ struct
+ {
+ u8 RSEQ:1;
+ u8 RXFNE:1;
+ u8 SNDET:1;
+ u8 SDET:1;
+ u8 CCDET:1;
+ u8 CADET:1;
+ u8 ACDET:1;
+ u8 AADET:1;
+ } reg0c;
+ //0D P2DET PNDET S1DET SCR1 U1DET - TXFNF -
+ struct
+ {
+ u8 nil2:1;
+ u8 TXFNF:1;
+ u8 nil1:1;
+ u8 U1DET:1;
+ u8 SCR1:1;
+ u8 S1DET:1;
+ u8 PNDET:1;
+ u8 P2DET:1;
+ } reg0d;
+ //0E RTDET BRKD RREDT SPEED
+ struct
+ {
+ u8 SPEED:5;
+ u8 RREDT:1;
+ u8 BRKD:1;
+ u8 RTDET:1;
+ } reg0e;
+ //0F RLSD FED CTS DSR RI TM RTSDT V54DT
+ struct
+ {
+ u8 V54DT:1;
+ u8 RTSDT:1;
+ u8 TM:1;
+ u8 RI:1;
+ u8 DSR:1;
+ u8 CTS:1;
+ u8 FED:1;
+ u8 RLSD:1;
+ } reg0f;
+ //10 Transmit Data Buffer (TBUFFER)/Voice Transmit Buffer (VBUFT)
+ u8 reg10;
+ //11 BRKS PARSL TXV RXV V23HDX TEOF TXP
+ struct
+ {
+ u8 TXP:1;
+ u8 TEOF:1;
+ u8 V23HDX:1;
+ u8 RXV:1;
+ u8 TXV:1;
+ u8 PARSL:2;
+ u8 BRKS:1;
+ } reg11;
+ //12 Configuration (CONF)
+ u8 reg12;
+ //13 TLVL RTH TXCLK
+ struct
+ {
+ u8 TLVL:4;
+ u8 RTH:2;
+ u8 TXCLK:2;
+ } reg13;
+ //14 ABCODE
+ u8 reg14;
+ //15 SLEEP - RDWK HWRWK AUTO RREN EXL3 EARC
+ struct
+ {
+ u8 EARC:1;
+ u8 EXL3:1;
+ u8 RREN:1;
+ u8 AUTO:1;
+ u8 HWRWK:1;
+ u8 RDWK:1;
+ u8 STOP:1;
+ u8 SLEEP:1;
+ } reg15;
+ //16 Secondary Receive Data Buffer/V.34 Receive Status (SECRXB)
+ u8 reg16;
+ //17 Secondary Transmit Data Buffer/V.34 Transmit Status(SECTXB)
+ u8 reg17;
+ //18 Memory Access Data LSB B7-B0 (MEDAL)
+ //19 Memory Access Data MSB B15-B8 (MEDAM)
+ u16 reg18_19;
+ //1A SFRES RIEN RION DMAE - SCOBF SCIBE SECEN
+ struct
+ {
+ u8 SECEN:1;
+ u8 SCIBE:1;
+ u8 SCOBF:1;
+ u8 nil:1;
+ u8 DMAE:1;
+ u8 RION:1;
+ u8 RIEN:1;
+ u8 SFRES:1;
+ } reg1a;
+ //1B EDET DTDET OTS DTMFD DTMFW
+ struct
+ {
+ u8 DTMFW:4;
+ u8 DTMFD:1;
+ u8 OTS:1;
+ u8 DTDET:1;
+ u8 EDET:1;
+ } reg1b;
+ //1C Memory Access Address Low B7-B0 (MEADDL)
+ //1D MEACC - MEMW MEMCR Memory Access Address High B11-B8 (MEADDH)
+ struct
+ {
+ u8 MEMADD_l:8; //anything else exept u8 breaks it ? WTFH ?
+ u8 MEMADD_h:4;
+ u8 MEMCR:1;
+ u8 MEMW:1;
+ u8 nil:1;
+ u8 MEACC:1;
+ } reg1c_1d;
+ //1E TDBIA RDBIA TDBIE - TDBE RDBIE - RDBF
+ struct
+ {
+ u8 RDBF:1;
+ u8 nil:1;
+ u8 RDBIE:1;
+ u8 TDBE:1;
+ u8 nil2:1;
+ u8 TDBIE:1;
+ u8 RDBIA:1;
+ u8 TDBIA:1;
+ } reg1e;
+ //1F NSIA NCIA - NSIE NEWS NCIE - NEWC
+ struct
+ {
+ u8 NEWC:1;
+ u8 nil:1;
+ u8 NCIE:1;
+ u8 NEWS :1;
+ u8 NSIE:1;
+ u8 nil2:1;
+ u8 NCIA:1;
+ u8 NSIA:1;
+ } reg1f;
+ };
+};
+
+u8 regs_write_mask[] = {
+ //00 Receive Data Buffer (RBUFFER)/Voice Receive Data Buffer (VBUFR)
+ 0xFF,
+ //01 VOLUME VPAUSE - - (TXHF RXHF RXP)
+ 0xE0,
+ //02 TDE SQDIS S511 - RTSDE V54TE V54AE V54PE
+ // DCDEN CDEN - - CODBITS (ignored)
+ 0xEF,
+ //03 EPT SEPT SRCEN RLSDE - - GTE GTS
+ 0xF3,
+ //04 RB - - FIFOEN - NRZIEN/VAGC TOD STRN
+ 0x95,
+ //05 - - - TXSQ CEQ - STOFF -
+ 0x3A,
+ //06 - EXOS CCRTN HDLC PEN STB WDSZ/DECBITS
+ 0x7F,
+ //07 RDLE RDL L2ACT - L3ACT - RA MHLD
+ 0xEB,
+ //08 ASYN TPDM V21S V54T V54A V54P RTRN RTS
+ 0xFF,
+ //09 NV25 CC DTMF ORG LL DATA RRTSE DTR
+ 0xFF,
+ //0A (PNSUC FLAGDT PE FE) OE (CRCS FLAGS SYNCD)
+ 0x08,
+ //0B (TONEA TONEB TONEC ATV25 ATBEL) - DISDET EQMAT
+ 0x03,
+ //0C (AADET ACDET CADET CCDET SDET SNDET RXFNE) RSEQ
+ 0x01,
+ //0D (P2DET PNDET S1DET SCR1 U1DET - TXFNF -)
+ 0x00,
+ //0E (RTDET BRKD) RREDT (SPEED)
+ 0x20,
+ //0F (RLSD FED CTS DSR RI TM) RTSDT V54DT
+ 0x03,
+ //10 Transmit Data Buffer (TBUFFER)/Voice Transmit Buffer (VBUFT)
+ 0xFF,
+ //11 BRKS PARSL TXV RXV V23HDX TEOF TXP
+ 0xFF,
+ //12 Configuration (CONF)
+ 0xFF,
+ //13 TLVL RTH TXCLK
+ 0xFF,
+ //14 ABCODE
+ 0xFF,
+ //15 SLEEP STOP RDWK HWRWK AUTO RREN EXL3 EARC
+ 0xFF,
+ //16 Secondary Receive Data Buffer/V.34 Receive Status (SECRXB)
+ 0xFF,
+ //17 Secondary Transmit Data Buffer/V.34 Transmit Status(SECTXB)
+ 0xFF,
+ //18 Memory Access Data LSB B7-B0 (MEDAL)
+ 0xFF,
+ //19 Memory Access Data MSB B15-B8 (MEDAM)
+ 0xFF,
+ //1A SFRES RIEN RION DMAE - SCOBF SCIBE SECEN
+ 0xF7,
+ //1B (EDET DTDET OTS DTMFD DTMFW)
+ 0x00,
+ //1C Memory Access Address Low B7-B0 (MEADDL)
+ 0xFF,
+ //1D MEACC - MEMW MEMCR Memory Access Address High B11-B8 (MEADDH)
+ 0xBF,
+ //1E TDBIA RDBIA TDBIE - TDBE RDBIE - RDBF
+ 0x24,
+ //1F NSIA NCIA - NSIE NEWS NCIE - NEWC
+ 0x1D,
+ //20 reset
+ 0xFF,
+};
+
+u32 regs_int_mask_addr[0x21] {
+ 0,
+ 0x247, // 01
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0x246, // 0A
+ 0x245, // 0B
+ 0x244, // 0C
+ 0x243, // 0D
+ 0x242, // 0E
+ 0x241, // 0F
+ 0,
+ 0,
+ 0x089, // 12
+ 0,
+ 0x38a, // 14
+ 0,
+ 0x370, // 16
+ 0x371, // 17
+ 0,
+ 0,
+ 0x27d, // 1A
+ 0x27c, // 1B
+ 0,
+};
+
+// Power-on reset DSP RAM
+static const u8 por_dspram[] =
+{
+/* 0x000 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x010 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x020 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x030 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x040 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x050 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x060 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x070 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x080 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x090 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x0A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x0B0 */ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x0C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x0D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x0E0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x0F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+/* 0x100 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x110 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x130 */ 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x140 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x150 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x160 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x170 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x180 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x190 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x1A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x1B0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x1C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x1D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x1E0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x1F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+/* 0x200 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x210 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDD, 0xAD, 0x08, 0x07, 0x99, 0x00, 0x23, 0xA0,
+/* 0x220 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00,
+/* 0x230 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x240 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x250 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x260 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 26F Saved Filtered EQM (???)
+/* 0x270 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x280 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00,
+/* 0x290 */ 0x32, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x19, 0x85, 0x20, 0x00,
+/* 0x2A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x2B0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x2C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x2D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x2E0 */ 0x00, 0x00, 0x00, 0x00, 0x0D, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // K56flex/V.34 Transmitter/Receiver Speed
+/* 0x2F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+/* 0x300 */ 0x00, 0x00, 0x00, 0x00, 0xC0, 0x28, 0x40, 0x03, 0x84, 0xCC, 0x00, 0x76, 0x84, 0xB1, 0x14, 0x02, // 304-8 V.8 Host Control Bits, 309-314 Modulation Modes
+/* 0x310 */ 0x08, 0x08, 0xA4, 0xA4, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x320 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCB, 0x00, 0x00, 0x00, // 32C: Receive FIFO Trigger Level
+/* 0x330 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x340 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x350 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x360 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x370 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x380 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x390 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x3A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x3B0 */ 0x20, 0x1A, 0x12, 0x0C, 0x0A, 0x09, 0x05, 0x03, 0x02, 0x00, 0x90, 0x28, 0x10, 0x04, 0x01, 0x00, // ARA Thresholds
+/* 0x3C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x3D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
+/* 0x3E0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x3F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+/* 0x400 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x410 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x420 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x430 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x440 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x450 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x460 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x470 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x480 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x490 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x4A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x4B0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x4C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x4D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x4E0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x4F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+/* 0x500 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x510 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x520 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x530 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x540 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x550 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x560 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x570 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x580 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x590 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x5A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x5B0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x5C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x5D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x5E0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x5F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+/* 0x600 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x610 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x620 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x630 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x640 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x650 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x660 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x670 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x680 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x690 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x6A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x6B0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x6C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x6D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x6E0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x6F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+/* 0x700 */ 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x710 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x720 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x730 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x740 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x750 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x760 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x770 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x780 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x790 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x7A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x7B0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x7C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x7D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x7E0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x7F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+/* 0x800 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x810 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x820 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x830 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x840 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x850 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x860 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x870 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x880 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x890 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x8A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x8B0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x8C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x8D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x8E0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x8F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+/* 0x900 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x910 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x920 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x930 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x940 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x950 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x960 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x970 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x980 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x990 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x9A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x9B0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x9C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x9D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x9E0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x9F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+/* 0xA00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xA10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xA20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xA30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xA40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xA50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xA60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xA70 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xA80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xA90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xAA0 */ 0x00, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x02, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCF, 0x00, 0x00,
+/* 0xAB0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xAC0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xAD0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xAE0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xAF0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+/* 0xB00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xB10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xB20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xB30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xB40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xB50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xB60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xB70 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xB80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xB90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xBA0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xBB0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xBC0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xBD0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xBE0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xBF0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+/* 0xC00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xC10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xC20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xC30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xC40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xC50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xC60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xC70 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xC80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xC90 */ 0x00, 0x00, 0x00, 0x00, 0x1B, 0x2D, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // C96 Minimum Off Time (DTMF), C95 Positive Twist Control
+/* 0xCA0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xCB0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xCC0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xCD0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xCE0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xCF0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+/* 0xD00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xD10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xD20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xD30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xD40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xD50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xD60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xD70 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xD80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xD90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xDA0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xDB0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xDC0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xDD0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xDE0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xDF0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+/* 0xE00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xE10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xE20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xE30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xE40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xE50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xE60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xE70 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xE80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xE90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // E96 Minimum On Time (DTMF)
+/* 0xEA0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xEB0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xEC0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xED0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xEE0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xEF0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+/* 0xF00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xF10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xF20 */ 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F21 ADC Speech Sample Scaling Parameter
+/* 0xF30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xF40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xF50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xF60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xF70 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xF80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xF90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xFA0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xFB0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xFC0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xFD0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xFE0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0xFF0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
diff --git a/core/hw/modem/pppd.cpp b/core/hw/modem/pppd.cpp
new file mode 100644
index 000000000..aa0bc9445
--- /dev/null
+++ b/core/hw/modem/pppd.cpp
@@ -0,0 +1,159 @@
+/*
+ pppd.cpp
+
+ Created on: Sep 10, 2018
+
+ Copyright 2018 flyinghead
+
+ This file is part of reicast.
+
+ reicast is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ reicast is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with reicast. If not, see .
+ */
+
+#if HOST_OS == OS_LINUX
+
+#include
+#include
+#include
+#include
+#include
+#include "pppd.h"
+
+static int pppd_pid;
+static int inpipe = -1;
+static int outpipe = -1;
+
+static u8 in_buffer[128];
+static int in_bufsize;
+static int in_bufindex;
+
+void start_pppd()
+{
+ int inpipefd[2];
+ int outpipefd[2];
+
+ if (pipe(inpipefd) || pipe(outpipefd))
+ {
+ perror("pipe");
+ return;
+ }
+ pppd_pid = fork();
+ if (pppd_pid < 0)
+ {
+ perror("fork");
+ close(inpipefd[0]);
+ close(inpipefd[1]);
+ close(outpipefd[0]);
+ close(outpipefd[1]);
+ return;
+ }
+
+ if (pppd_pid == 0)
+ {
+ // Child
+ close(inpipefd[0]);
+ dup2(inpipefd[1], 1);
+ close(outpipefd[1]);
+ dup2(outpipefd[0], 0);
+ execl("/usr/sbin/pppd", "pppd", "notty", NULL);
+ perror("execl");
+ exit(1);
+ }
+ // Parent
+ inpipe = inpipefd[0];
+ outpipe = outpipefd[1];
+ fcntl(inpipe, F_SETFL, fcntl(inpipe, F_GETFL) | O_NONBLOCK);
+}
+
+void stop_pppd()
+{
+ if (pppd_pid > 0)
+ {
+ kill(SIGTERM, pppd_pid);
+ // FIXME wait / waitpid
+ pppd_pid = 0;
+ }
+ if (inpipe >= 0)
+ {
+ close(inpipe);
+ inpipe = -1;
+ }
+ if (outpipe >= 0)
+ {
+ close(outpipe);
+ outpipe = -1;
+ }
+}
+
+void write_pppd(u8 b)
+{
+ int rc = write(outpipe, &b, 1);
+ if (rc < 0)
+ perror("write outpipe");
+ else if (rc == 0)
+ printf("pppd EOF on outpipe\n");
+}
+
+int read_pppd()
+{
+ if (in_bufindex == in_bufsize)
+ {
+ int rc = read(inpipe, in_buffer, sizeof(in_buffer));
+ if (rc < 0)
+ {
+ if (errno != EWOULDBLOCK)
+ perror("read inpipe");
+ return rc;
+ }
+ else if (rc == 0)
+ {
+ printf("pppd EOF on inpipe\n");
+ return -1;
+ }
+ in_bufsize = rc;
+ in_bufindex = 0;
+ }
+ return in_buffer[in_bufindex++];
+}
+
+int avail_pppd()
+{
+ return in_bufsize - in_bufindex;
+}
+
+#else // not Linux
+
+void start_pppd()
+{
+}
+
+void stop_pppd()
+{
+}
+
+void write_pppd(u8 b)
+{
+}
+
+int read_pppd()
+{
+ return -1;
+}
+
+int avail_pppd() {
+ return 0;
+}
+
+#endif
+
diff --git a/core/hw/modem/pppd.h b/core/hw/modem/pppd.h
new file mode 100644
index 000000000..83f49dc51
--- /dev/null
+++ b/core/hw/modem/pppd.h
@@ -0,0 +1,34 @@
+/*
+ pppd.h
+
+ Created on: Sep 10, 2018
+
+ Copyright 2018 flyinghead
+
+ This file is part of reicast.
+
+ reicast is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ reicast is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with reicast. If not, see .
+ */
+
+#ifndef CORE_HW_MODEM_PPPD_H_
+#define CORE_HW_MODEM_PPPD_H_
+#include "types.h"
+
+void start_pppd();
+void stop_pppd();
+void write_pppd(u8 b);
+int read_pppd();
+int avail_pppd();
+
+#endif /* CORE_HW_MODEM_PPPD_H_ */
diff --git a/core/types.h b/core/types.h
index 26743e0ad..4f6004868 100644
--- a/core/types.h
+++ b/core/types.h
@@ -841,8 +841,11 @@ s32 libExtDevice_Init();
void libExtDevice_Reset(bool M);
void libExtDevice_Term();
+#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
+// 0x00600000 - 0x006007FF [Modem]
static u32 libExtDevice_ReadMem_A0_006(u32 addr,u32 size) { return 0; }
static void libExtDevice_WriteMem_A0_006(u32 addr,u32 data,u32 size) { }
+#endif
//Area 0 , 0x01000000- 0x01FFFFFF [Ext. Device]
static u32 libExtDevice_ReadMem_A0_010(u32 addr,u32 size) { return 0; }