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; }