From 2fecef07414274e418f6d209e7de766704ee8938 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Thu, 19 Jul 2018 16:01:31 +0200 Subject: [PATCH] Preliminary 186 emulation. Added MCA variant of the ET4000 VGA card. Added NE/2 Netware card. Corrected timings of the NCR 5380-based cards. Added the WD8003E (8-bit ISA), WD8013EBT (16-bit ISA) and WD8013EP/A (MCA) network cards. --- src/cpu/808x.c | 141 ++- src/cpu/cpu.c | 5 +- src/cpu/cpu.h | 60 +- src/cpu/cpu_table.c | 19 +- src/machine/m_ps2_mca.c | 13 +- src/machine/machine_table.c | 60 +- src/network/net_ne2000.c | 346 +++++-- src/network/net_ne2000.h | 10 +- src/network/net_wd8003.c | 1733 +++++++++++++++++++++++++++++++++++ src/network/net_wd8003.h | 49 + src/network/network.c | 9 + src/scsi/scsi_ncr5380.c | 1486 +++++++++++++++++++++--------- src/video/vid_et4000.c | 82 +- src/video/vid_et4000.h | 3 +- src/video/vid_table.c | 5 +- src/video/video.h | 3 +- src/win/Makefile.mingw | 3 +- 17 files changed, 3382 insertions(+), 645 deletions(-) create mode 100644 src/network/net_wd8003.c create mode 100644 src/network/net_wd8003.h diff --git a/src/cpu/808x.c b/src/cpu/808x.c index 53e2403cc..1f5a738eb 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -881,19 +881,70 @@ void rep(int fv) cycles-=2; goto startrep; break; - case 0x6E: /*REP OUTSB*/ - if (c>0) - { - temp2=readmemb(ds+SI); - outb(DX,temp2); - if (flags&D_FLAG) SI--; - else SI++; - c--; - cycles-=5; - } - if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } - else firstrepcycle=1; + case 0x6C: /*186+ REP INSB*/ + if (is186) + { + if (c>0) + { + temp2=inb(DX); + writememb(ds+SI, temp2); + if (flags&D_FLAG) SI--; + else SI++; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + } + break; + case 0x6D: /*186+ REP INSW*/ + if (is186) + { + if (c>0) + { + tempw2=inw(DX); + writememw(ds, SI, tempw2); + if (flags&D_FLAG) SI-=2; + else SI+=2; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + } break; + case 0x6E: /*186+ REP OUTSB*/ + if (is186) + { + if (c>0) + { + temp2=readmemb(ds+SI); + outb(DX,temp2); + if (flags&D_FLAG) SI--; + else SI++; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + } + break; + case 0x6F: /*186+ REP OUTSW*/ + if (is186) + { + if (c>0) + { + tempw2=readmemw(ds,SI); + outw(DX,tempw2); + if (flags&D_FLAG) SI-=2; + else SI+=2; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + } + break; case 0xA4: /*REP MOVSB*/ while (c>0 && !IRQTEST) { @@ -2282,7 +2333,50 @@ void execx86(int cycs) cycles-=((cpu_mod==3)?4:14); break; - case 0xC8: /*RETF alias*/ + case 0xC8: /*186+ ENTER*/ + if (is186) + { + int count; + + tempw=readmemw(ss,SP); + tempw2=readmemw(ss,(SP+2)&0xFFFF); + tempw3=CS; + tempw4=cpu_state.pc; + + if (cpu_state.ssegs) ss=oldss; + + count=geteaw(); + + if (count > 0) + { + while (--count) + { + cpu_state.pc=tempw; + loadcs(tempw2); + cycles-=4; + } + writememw(ss,(SP-2)&0xFFFF,tempw3); + writememw(ss,((SP-4)&0xFFFF),tempw4); + cycles-=5; + } + cpu_state.last_ea = SP; + SP-=getword(); + cycles-=10; + FETCHCLEAR(); + } + else /*RETF alias*/ + { + tempw=getword(); + if (cpu_state.ssegs) ss=oldss; + cpu_state.pc=readmemw(ss,SP); + loadcs(readmemw(ss,SP+2)); + SP+=4; + SP+=tempw; + cycles-=33; + FETCHCLEAR(); + } + break; + case 0xCA: /*RETF*/ tempw=getword(); if (cpu_state.ssegs) ss=oldss; @@ -2293,7 +2387,26 @@ void execx86(int cycs) cycles-=33; FETCHCLEAR(); break; - case 0xC9: /*RETF alias*/ + case 0xC9: + if (is186) /*186+ LEAVE*/ + { + if (cpu_state.ssegs) ss=oldss; + + cpu_state.regs[opcode&7].w=readmemw(ss,(SP-2)&0xFFFF); + cpu_state.last_ea = SP; + cycles-=4; + } + else /*RETF alias*/ + { + if (cpu_state.ssegs) ss=oldss; + cpu_state.pc=readmemw(ss,SP); + loadcs(readmemw(ss,SP+2)); + SP+=4; + cycles-=34; + FETCHCLEAR(); + } + break; + case 0xCB: /*RETF*/ if (cpu_state.ssegs) ss=oldss; cpu_state.pc=readmemw(ss,SP); diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index cd5804b71..889083304 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -132,7 +132,8 @@ int cpu_waitstates; int cpu_cache_int_enabled, cpu_cache_ext_enabled; int cpu_pci_speed; -int is286, +int is186, + is286, is386, is486, cpu_iscyrix, @@ -243,6 +244,7 @@ cpu_set(void) CPUID = cpu_s->cpuid_model; cpuspeed = cpu_s->speed; is8086 = (cpu_s->cpu_type > CPU_8088); + is186 = (cpu_s->cpu_type == CPU_186); is286 = (cpu_s->cpu_type >= CPU_286); is386 = (cpu_s->cpu_type >= CPU_386SX); israpidcad = (cpu_s->cpu_type == CPU_RAPIDCAD); @@ -395,6 +397,7 @@ cpu_set(void) { case CPU_8088: case CPU_8086: + case CPU_186: break; case CPU_286: diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index b4efb8a3c..67a818339 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -24,42 +24,43 @@ #define CPU_8088 0 /* 808x class CPUs */ #define CPU_8086 1 -#define CPU_286 2 /* 286 class CPUs */ -#define CPU_386SX 3 /* 386 class CPUs */ -#define CPU_386DX 4 -#define CPU_RAPIDCAD 5 -#define CPU_486SLC 6 -#define CPU_486DLC 7 -#define CPU_i486SX 8 /* 486 class CPUs */ -#define CPU_Am486SX 9 -#define CPU_Cx486S 10 -#define CPU_i486DX 11 -#define CPU_Am486DX 12 -#define CPU_Cx486DX 13 -#define CPU_iDX4 14 -#define CPU_Cx5x86 15 -#define CPU_WINCHIP 16 /* 586 class CPUs */ -#define CPU_PENTIUM 17 -#define CPU_PENTIUMMMX 18 -#define CPU_Cx6x86 19 -#define CPU_Cx6x86MX 20 -#define CPU_Cx6x86L 21 -#define CPU_CxGX1 22 +#define CPU_186 2 +#define CPU_286 3 /* 286 class CPUs */ +#define CPU_386SX 4 /* 386 class CPUs */ +#define CPU_386DX 5 +#define CPU_RAPIDCAD 6 +#define CPU_486SLC 7 +#define CPU_486DLC 8 +#define CPU_i486SX 9 /* 486 class CPUs */ +#define CPU_Am486SX 10 +#define CPU_Cx486S 11 +#define CPU_i486DX 12 +#define CPU_Am486DX 13 +#define CPU_Cx486DX 14 +#define CPU_iDX4 15 +#define CPU_Cx5x86 16 +#define CPU_WINCHIP 17 /* 586 class CPUs */ +#define CPU_PENTIUM 18 +#define CPU_PENTIUMMMX 19 +#define CPU_Cx6x86 20 +#define CPU_Cx6x86MX 21 +#define CPU_Cx6x86L 22 +#define CPU_CxGX1 23 #ifdef DEV_BRANCH #ifdef USE_AMD_K -#define CPU_K5 23 -#define CPU_5K86 24 -#define CPU_K6 25 +#define CPU_K5 24 +#define CPU_5K86 25 +#define CPU_K6 26 #endif #endif #ifdef DEV_BRANCH #ifdef USE_I686 -#define CPU_PENTIUMPRO 26 /* 686 class CPUs */ +#define CPU_PENTIUMPRO 27 /* 686 class CPUs */ #if 0 -# define CPU_PENTIUM2 27 -# define CPU_PENTIUM2D 28 +# define CPU_PENTIUM2 28 +# define CPU_PENTIUM2D 29 #else -# define CPU_PENTIUM2D 27 +# define CPU_PENTIUM2D 28 #endif #endif #endif @@ -91,6 +92,7 @@ typedef struct { extern CPU cpus_8088[]; extern CPU cpus_8086[]; +extern CPU cpus_186[]; extern CPU cpus_286[]; extern CPU cpus_i386SX[]; extern CPU cpus_i386DX[]; @@ -315,7 +317,7 @@ extern int cpu_multi; extern int cpu_cyrix_alignment; /*Cyrix 5x86/6x86 only has data misalignment penalties when crossing 8-byte boundaries*/ -extern int is8086, is286, is386, is486; +extern int is8086, is186, is286, is386, is486; extern int is_rapidcad, is_pentium; extern int hasfpu; extern int cpu_hasrdtsc; diff --git a/src/cpu/cpu_table.c b/src/cpu/cpu_table.c index bf978c9fc..5bd861635 100644 --- a/src/cpu/cpu_table.c +++ b/src/cpu/cpu_table.c @@ -29,7 +29,7 @@ * 16 = 180 MHz * 17 = 200 MHz * - * Version: @(#)cpu_table.c 1.0.5 2018/07/17 + * Version: @(#)cpu_table.c 1.0.4 2018/02/18 * * Authors: Sarah Walker, * leilei, @@ -54,12 +54,10 @@ CPU cpus_8088[] = { /*8088 standard*/ {"8088/4.77", CPU_8088, 0, 4772728, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, {"8088/8", CPU_8088, 1, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, -#if 0 {"8088/7.16", CPU_8088, 1, 14318184/2, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, {"8088/10", CPU_8088, 2, 10000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, {"8088/12", CPU_8088, 3, 12000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, - {"8088/16", CPU_8088, 4, 16000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, -#endif + {"8088/16", CPU_8088, 4, 16000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 2}, {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} }; @@ -88,6 +86,19 @@ CPU cpus_8086[] = { {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} }; +CPU cpus_186[] = { + /*80186 standard*/ + {"80186/7.16", CPU_186, 1, 14318184/2, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"80186/8", CPU_186, 1, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"80186/9.54", CPU_186, 1, 4772728*2, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"80186/10", CPU_186, 2, 10000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"80186/12", CPU_186, 3, 12000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"80186/16", CPU_186, 4, 16000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 2}, + {"80186/20", CPU_186, 5, 20000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 3}, + {"80186/25", CPU_186, 6, 25000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 3}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + CPU cpus_pc1512[] = { /*8086 Amstrad*/ {"8086/8", CPU_8086, 1, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index 1d594860d..d0c02a579 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -24,6 +24,7 @@ #include "../lpt.h" #include "../mouse.h" #include "../serial.h" +#include "../video/video.h" #include "../video/vid_vga.h" #include "machine.h" @@ -841,7 +842,8 @@ static void ps2_mca_board_model_50_init() ps2_mca_mem_fffc_init(2); } - device_add(&ps1vga_device); + if (gfxcard == GFX_INTERNAL) + device_add(&ps1vga_device); } static void ps2_mca_board_model_55sx_init() @@ -905,7 +907,8 @@ static void ps2_mca_board_model_55sx_init() ps2.planar_read = model_55sx_read; ps2.planar_write = model_55sx_write; - device_add(&ps1vga_device); + if (gfxcard == GFX_INTERNAL) + device_add(&ps1vga_device); } static void mem_encoding_update() @@ -1112,7 +1115,8 @@ static void ps2_mca_board_model_70_type34_init(int is_type4) ps2_mca_mem_fffc_init(8); } - device_add(&ps1vga_device); + if (gfxcard == GFX_INTERNAL) + device_add(&ps1vga_device); } static void ps2_mca_board_model_80_type2_init(int is486) @@ -1181,7 +1185,8 @@ static void ps2_mca_board_model_80_type2_init(int is486) ps2_mca_mem_fffc_init(4); } - device_add(&ps1vga_device); + if (gfxcard == GFX_INTERNAL) + device_add(&ps1vga_device); } diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index c1f89623b..b7dd154af 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -11,7 +11,7 @@ * NOTES: OpenAT wip for 286-class machine with open BIOS. * PS2_M80-486 wip, pending receipt of TRM's for machine. * - * Version: @(#)machine_table.c 1.0.30 2018/05/26 + * Version: @(#)machine_table.c 1.0.31 2018/07/07 * * Authors: Sarah Walker, * Miran Grca, @@ -34,34 +34,34 @@ const machine_t machines[] = { - { "[8088] AMI XT clone", ROM_AMIXT, "amixt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, - { "[8088] Compaq Portable", ROM_PORTABLE, "portable", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO, 128, 640, 128, 0, machine_xt_compaq_init, NULL }, - { "[8088] DTK XT clone", ROM_DTKXT, "dtk", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, - { "[8088] IBM PC", ROM_IBMPC, "ibmpc", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 32, 0, machine_xt_init, NULL }, - { "[8088] IBM PCjr", ROM_IBMPCJR, "ibmpcjr", {{"", cpus_pcjr}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 128, 640, 128, 0, machine_pcjr_init, pcjr_get_device }, - { "[8088] IBM XT", ROM_IBMXT, "ibmxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, - { "[8088] Generic XT clone", ROM_GENXT, "genxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, - { "[8088] Juko XT clone", ROM_JUKOPC, "jukopc", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, - { "[8088] Phoenix XT clone", ROM_PXXT, "pxxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, - { "[8088] Schneider EuroPC", ROM_EUROPC, "europc", {{"Siemens",cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_HDC | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 15, machine_europc_init, NULL }, - { "[8088] Tandy 1000", ROM_TANDY, "tandy", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 128, 640, 128, 0, machine_tandy1k_init, tandy1k_get_device }, - { "[8088] Tandy 1000 HX", ROM_TANDY1000HX, "tandy1000hx", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 256, 640, 128, 0, machine_tandy1k_init, tandy1k_hx_get_device }, - { "[8088] Toshiba T1000", ROM_T1000, "t1000", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 512, 1280, 768, 63, machine_xt_t1000_init, NULL }, + { "[8088] AMI XT clone", ROM_AMIXT, "amixt", {{"Intel", cpus_8088}, {"Intel", cpus_186}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, + { "[8088] Compaq Portable", ROM_PORTABLE, "portable", {{"Intel", cpus_8088}, {"Intel", cpus_186}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO, 128, 640, 128, 0, machine_xt_compaq_init, NULL }, + { "[8088] DTK XT clone", ROM_DTKXT, "dtk", {{"Intel", cpus_8088}, {"Intel", cpus_186}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, + { "[8088] IBM PC", ROM_IBMPC, "ibmpc", {{"Intel", cpus_8088}, {"Intel", cpus_186}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 32, 0, machine_xt_init, NULL }, + { "[8088] IBM PCjr", ROM_IBMPCJR, "ibmpcjr", {{"Intel", cpus_pcjr}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 128, 640, 128, 0, machine_pcjr_init, pcjr_get_device }, + { "[8088] IBM XT", ROM_IBMXT, "ibmxt", {{"Intel", cpus_8088}, {"Intel", cpus_186}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, + { "[8088] Generic XT clone", ROM_GENXT, "genxt", {{"Intel", cpus_8088}, {"Intel", cpus_186}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, + { "[8088] Juko XT clone", ROM_JUKOPC, "jukopc", {{"Intel", cpus_8088}, {"Intel", cpus_186}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, + { "[8088] Phoenix XT clone", ROM_PXXT, "pxxt", {{"Intel", cpus_8088}, {"Intel", cpus_186}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, + { "[8088] Schneider EuroPC", ROM_EUROPC, "europc", {{"Siemens", cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_HDC | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 15, machine_europc_init, NULL }, + { "[8088] Tandy 1000", ROM_TANDY, "tandy", {{"Intel", cpus_8088}, {"Intel", cpus_186}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 128, 640, 128, 0, machine_tandy1k_init, tandy1k_get_device }, + { "[8088] Tandy 1000 HX", ROM_TANDY1000HX, "tandy1000hx", {{"Intel", cpus_8088}, {"Intel", cpus_186}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 256, 640, 128, 0, machine_tandy1k_init, tandy1k_hx_get_device }, + { "[8088] Toshiba T1000", ROM_T1000, "t1000", {{"Intel", cpus_8088}, {"Intel", cpus_186}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 512, 1280, 768, 63, machine_xt_t1000_init, NULL }, #if defined(DEV_BRANCH) && defined(USE_LASERXT) - { "[8088] VTech Laser Turbo XT", ROM_LTXT, "ltxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 512, 512, 256, 0, machine_xt_laserxt_init, NULL }, + { "[8088] VTech Laser Turbo XT", ROM_LTXT, "ltxt", {{"Intel", cpus_8088}, {"Intel", cpus_186},, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 512, 512, 256, 0, machine_xt_laserxt_init, NULL }, #endif - { "[8088] Xi8088", ROM_XI8088, "xi8088", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 64, 1024, 128, 127, machine_xt_xi8088_init, NULL }, + { "[8088] Xi8088", ROM_XI8088, "xi8088", {{"Intel", cpus_8088}, {"Intel", cpus_186}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 64, 1024, 128, 127, machine_xt_xi8088_init, NULL }, - { "[8086] Amstrad PC1512", ROM_PC1512, "pc1512", {{"", cpus_pc1512}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 63, machine_amstrad_init, NULL }, - { "[8086] Amstrad PC1640", ROM_PC1640, "pc1640", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_amstrad_init, NULL }, - { "[8086] Amstrad PC2086", ROM_PC2086, "pc2086", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_amstrad_init, NULL }, - { "[8086] Amstrad PC3086", ROM_PC3086, "pc3086", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_amstrad_init, NULL }, - { "[8086] Amstrad PC20(0)", ROM_PC200, "pc200", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 63, machine_amstrad_init, NULL }, - { "[8086] Olivetti M24", ROM_OLIM24, "olivetti_m24", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 128, 640, 128, 0, machine_olim24_init, NULL }, - { "[8086] Tandy 1000 SL/2", ROM_TANDY1000SL2, "tandy1000sl2", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 512, 768, 128, 0, machine_tandy1k_init, NULL }, - { "[8086] Toshiba T1200", ROM_T1200, "t1200", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 1024, 2048,1024, 63, machine_xt_t1200_init, NULL }, + { "[8086] Amstrad PC1512", ROM_PC1512, "pc1512", {{"Intel", cpus_pc1512}, {"Intel", cpus_186}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 63, machine_amstrad_init, NULL }, + { "[8086] Amstrad PC1640", ROM_PC1640, "pc1640", {{"Intel", cpus_8086}, {"Intel", cpus_186}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_amstrad_init, NULL }, + { "[8086] Amstrad PC2086", ROM_PC2086, "pc2086", {{"Intel", cpus_8086}, {"Intel", cpus_186}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_amstrad_init, NULL }, + { "[8086] Amstrad PC3086", ROM_PC3086, "pc3086", {{"Intel", cpus_8086}, {"Intel", cpus_186}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_amstrad_init, NULL }, + { "[8086] Amstrad PC20(0)", ROM_PC200, "pc200", {{"Intel", cpus_8086}, {"Intel", cpus_186}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 63, machine_amstrad_init, NULL }, + { "[8086] Olivetti M24", ROM_OLIM24, "olivetti_m24", {{"Intel", cpus_8086}, {"Intel", cpus_186}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 128, 640, 128, 0, machine_olim24_init, NULL }, + { "[8086] Tandy 1000 SL/2", ROM_TANDY1000SL2, "tandy1000sl2", {{"Intel", cpus_8086}, {"Intel", cpus_186}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 512, 768, 128, 0, machine_tandy1k_init, NULL }, + { "[8086] Toshiba T1200", ROM_T1200, "t1200", {{"Intel", cpus_8086}, {"Intel", cpus_186}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 1024, 2048,1024, 63, machine_xt_t1200_init, NULL }, #if defined(DEV_BRANCH) && defined(USE_LASERXT) - { "[8086] VTech Laser XT3", ROM_LXT3, "lxt3", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 256, 512, 256, 0, machine_xt_laserxt_init, NULL }, + { "[8086] VTech Laser XT3", ROM_LXT3, "lxt3", {{"Intel", cpus_8086}, {"Intel", cpus_186}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 256, 512, 256, 0, machine_xt_laserxt_init, NULL }, #endif { "[286 ISA] AMI 286 clone", ROM_AMI286, "ami286", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_neat_ami_init, NULL }, @@ -84,7 +84,7 @@ const machine_t machines[] = { #endif { "[286 ISA] Toshiba T3100e", ROM_T3100E, "t3100e", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1024, 5120, 256, 63, machine_at_t3100e_init, NULL }, - { "[286 MCA] IBM PS/2 model 50", ROM_IBMPS2_M50, "ibmps2_m50", {{"", cpus_ps2_m30_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 1, 10, 1, 63, machine_ps2_model_50_init, NULL }, + { "[286 MCA] IBM PS/2 model 50", ROM_IBMPS2_M50, "ibmps2_m50", {{"", cpus_ps2_m30_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2 | MACHINE_VIDEO, 1, 10, 1, 63, machine_ps2_model_50_init, NULL }, { "[386SX ISA] AMI 386SX clone", ROM_AMI386SX, "ami386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512,16384, 128, 127, machine_at_headland_init, NULL }, { "[386SX ISA] Amstrad MegaPC", ROM_MEGAPC, "megapc", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO | MACHINE_HDC, 1, 16, 1, 127, machine_at_wd76c10_init, NULL }, @@ -94,7 +94,7 @@ const machine_t machines[] = { { "[386SX ISA] IBM PS/1 m.2121+ISA", ROM_IBMPS1_2121_ISA, "ibmps1_2121_isa", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 6, 1, 63, machine_ps1_m2121_init, NULL }, { "[386SX ISA] KMX-C-02", ROM_KMXC02, "kmxc02", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 512, 127, machine_at_scatsx_init, NULL }, - { "[386SX MCA] IBM PS/2 model 55SX", ROM_IBMPS2_M55SX, "ibmps2_m55sx", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 1, 8, 1, 63, machine_ps2_model_55sx_init, NULL }, + { "[386SX MCA] IBM PS/2 model 55SX", ROM_IBMPS2_M55SX, "ibmps2_m55sx", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2 | MACHINE_VIDEO, 1, 8, 1, 63, machine_ps2_model_55sx_init, NULL }, { "[386DX ISA] AMI 386DX clone", ROM_AMI386DX_OPTI495, "ami386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_ami_init, NULL }, { "[386DX ISA] Amstrad MegaPC 386DX", ROM_MEGAPCDX, "megapcdx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 32, 1, 127, machine_at_wd76c10_init, NULL }, @@ -104,8 +104,8 @@ const machine_t machines[] = { { "[386DX ISA] Compaq Portable III (386)", ROM_PORTABLEIII386, "portableiii386", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_VIDEO, 1, 14, 1, 127, machine_at_compaq_init, NULL }, #endif - { "[386DX MCA] IBM PS/2 model 70 (type 3)", ROM_IBMPS2_M70_TYPE3, "ibmps2_m70_type3", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 2, 16, 2, 63, machine_ps2_model_70_type3_init, NULL }, - { "[386DX MCA] IBM PS/2 model 80", ROM_IBMPS2_M80, "ibmps2_m80", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 1, 12, 1, 63, machine_ps2_model_80_init, NULL }, + { "[386DX MCA] IBM PS/2 model 70 (type 3)", ROM_IBMPS2_M70_TYPE3, "ibmps2_m70_type3", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2 | MACHINE_VIDEO, 2, 16, 2, 63, machine_ps2_model_70_type3_init, NULL }, + { "[386DX MCA] IBM PS/2 model 80", ROM_IBMPS2_M80, "ibmps2_m80", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2 | MACHINE_VIDEO, 1, 12, 1, 63, machine_ps2_model_80_init, NULL }, { "[486 ISA] AMI 486 clone", ROM_AMI486, "ami486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_ali1429_init, NULL }, { "[486 ISA] AMI WinBIOS 486", ROM_WIN486, "win486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_ali1429_init, NULL }, @@ -113,7 +113,7 @@ const machine_t machines[] = { { "[486 ISA] DTK PKM-0038S E-2", ROM_DTK486, "dtk486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 128, 1, 127, machine_at_dtk486_init, NULL }, { "[486 ISA] IBM PS/1 model 2133", ROM_IBMPS1_2133, "ibmps1_2133", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 1, 64, 1, 127, machine_ps1_m2133_init, NULL }, - { "[486 MCA] IBM PS/2 model 70 (type 4)", ROM_IBMPS2_M70_TYPE4, "ibmps2_m70_type4", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 2, 16, 2, 63, machine_ps2_model_70_type4_init, NULL }, + { "[486 MCA] IBM PS/2 model 70 (type 4)", ROM_IBMPS2_M70_TYPE4, "ibmps2_m70_type4", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2 | MACHINE_VIDEO, 2, 16, 2, 63, machine_ps2_model_70_type4_init, NULL }, { "[486 PCI] Rise Computer R418", ROM_R418, "r418", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 255, 1, 127, machine_at_r418_init, NULL }, diff --git a/src/network/net_ne2000.c b/src/network/net_ne2000.c index 43a7b347f..9d50d8d18 100644 --- a/src/network/net_ne2000.c +++ b/src/network/net_ne2000.c @@ -12,7 +12,7 @@ * - Realtek RTL8019AS (ISA 16-bit, PnP); * - Realtek RTL8029AS (PCI). * - * Version: @(#)net_ne2000.c 1.0.4 2018/04/26 + * Version: @(#)net_ne2000.c 1.0.5 2018/07/11 * * Based on @(#)ne2k.cc v1.56.2.1 2004/02/02 22:37:22 cbothamy * @@ -57,6 +57,7 @@ #include "../io.h" #include "../mem.h" #include "../rom.h" +#include "../mca.h" #include "../pci.h" #include "../pic.h" #include "../random.h" @@ -75,7 +76,6 @@ enum { PNP_PHASE_SLEEP }; - /* ROM BIOS file paths. */ #define ROM_PATH_NE1000 L"roms/network/ne1000/ne1000.rom" #define ROM_PATH_NE2000 L"roms/network/ne2000/ne2000.rom" @@ -100,7 +100,7 @@ typedef struct { dp8390_t dp8390; uint8_t macaddr[32]; /* ASIC ROM'd MAC address, even bytes */ int board; - int is_pci, is_8bit; + int is_pci, is_mca, is_8bit; const char *name; uint32_t base_address; int base_irq; @@ -134,12 +134,20 @@ typedef struct { /* RTL8019AS/RTL8029AS registers */ uint8_t config0, config2, config3; uint8_t _9346cr; + + /* POS registers, MCA boards only */ + uint8_t pos_regs[8]; } nic_t; static void nic_rx(void *, uint8_t *, int); static void nic_tx(nic_t *, uint32_t); +#define ENABLE_NIC_LOG 3 + +#ifdef ENABLE_NIC_LOG +int nic_do_log = ENABLE_NIC_LOG; +#endif static void nelog(int lvl, const char *fmt, ...) @@ -182,37 +190,40 @@ nic_reset(void *priv) nelog(1, "%s: reset\n", dev->name); - if (dev->board >= NE2K_NE2000) { - /* Initialize the MAC address area by doubling the physical address */ - dev->macaddr[0] = dev->dp8390.physaddr[0]; - dev->macaddr[1] = dev->dp8390.physaddr[0]; - dev->macaddr[2] = dev->dp8390.physaddr[1]; - dev->macaddr[3] = dev->dp8390.physaddr[1]; - dev->macaddr[4] = dev->dp8390.physaddr[2]; - dev->macaddr[5] = dev->dp8390.physaddr[2]; - dev->macaddr[6] = dev->dp8390.physaddr[3]; - dev->macaddr[7] = dev->dp8390.physaddr[3]; - dev->macaddr[8] = dev->dp8390.physaddr[4]; - dev->macaddr[9] = dev->dp8390.physaddr[4]; - dev->macaddr[10] = dev->dp8390.physaddr[5]; - dev->macaddr[11] = dev->dp8390.physaddr[5]; + if (dev->board == NE2K_NE1000) + { + /* Initialize the MAC address area by doubling the physical address */ + dev->macaddr[0] = dev->dp8390.physaddr[0]; + dev->macaddr[1] = dev->dp8390.physaddr[1]; + dev->macaddr[2] = dev->dp8390.physaddr[2]; + dev->macaddr[3] = dev->dp8390.physaddr[3]; + dev->macaddr[4] = dev->dp8390.physaddr[4]; + dev->macaddr[5] = dev->dp8390.physaddr[5]; - /* ne2k signature */ - for (i=12; i<32; i++) - dev->macaddr[i] = 0x57; - } else { - /* Initialize the MAC address area by doubling the physical address */ - dev->macaddr[0] = dev->dp8390.physaddr[0]; - dev->macaddr[1] = dev->dp8390.physaddr[1]; - dev->macaddr[2] = dev->dp8390.physaddr[2]; - dev->macaddr[3] = dev->dp8390.physaddr[3]; - dev->macaddr[4] = dev->dp8390.physaddr[4]; - dev->macaddr[5] = dev->dp8390.physaddr[5]; + /* ne1k signature */ + for (i=6; i<16; i++) + dev->macaddr[i] = 0x57; + } + else + { + /* Initialize the MAC address area by doubling the physical address */ + dev->macaddr[0] = dev->dp8390.physaddr[0]; + dev->macaddr[1] = dev->dp8390.physaddr[0]; + dev->macaddr[2] = dev->dp8390.physaddr[1]; + dev->macaddr[3] = dev->dp8390.physaddr[1]; + dev->macaddr[4] = dev->dp8390.physaddr[2]; + dev->macaddr[5] = dev->dp8390.physaddr[2]; + dev->macaddr[6] = dev->dp8390.physaddr[3]; + dev->macaddr[7] = dev->dp8390.physaddr[3]; + dev->macaddr[8] = dev->dp8390.physaddr[4]; + dev->macaddr[9] = dev->dp8390.physaddr[4]; + dev->macaddr[10] = dev->dp8390.physaddr[5]; + dev->macaddr[11] = dev->dp8390.physaddr[5]; - /* ne1k signature */ - for (i=6; i<16; i++) - dev->macaddr[i] = 0x57; - } + /* ne2k signature */ + for (i=12; i<32; i++) + dev->macaddr[i] = 0x57; + } /* Zero out registers and memory */ memset(&dev->dp8390.CR, 0x00, sizeof(dev->dp8390.CR) ); @@ -233,8 +244,10 @@ nic_reset(void *priv) dev->dp8390.fifo = 0; dev->dp8390.remote_dma = 0; dev->dp8390.remote_start = 0; - dev->dp8390.remote_bytes = 0; - dev->dp8390.tallycnt_0 = 0; + + dev->dp8390.remote_bytes = 0; + + dev->dp8390.tallycnt_0 = 0; dev->dp8390.tallycnt_1 = 0; dev->dp8390.tallycnt_2 = 0; @@ -272,7 +285,7 @@ nic_soft_reset(void *priv) * The NE2000 memory is accessed through the data port of the * ASIC (offset 0) after setting up a remote-DMA transfer. * Both byte and word accesses are allowed. - * The first 16 bytes contains the MAC address at even locations, + * The first 16 bytes contain the MAC address at even locations, * and there is 16K of buffer memory starting at 16K. */ static uint32_t @@ -284,8 +297,10 @@ chipmem_read(nic_t *dev, uint32_t addr, unsigned int len) nelog(3, "%s: unaligned chipmem word read\n", dev->name); } + pclog("Chipmem Read Address=%04x\n", addr); + /* ROM'd MAC address */ - if (dev->board >= NE2K_NE2000) { + if (dev->board != NE2K_NE1000) { if (addr <= 31) { retval = dev->macaddr[addr % 32]; if ((len == 2) || (len == 4)) { @@ -351,7 +366,9 @@ chipmem_write(nic_t *dev, uint32_t addr, uint32_t val, unsigned len) nelog(3, "%s: unaligned chipmem word write\n", dev->name); } - if (dev->board >= NE2K_NE2000) { + pclog("Chipmem Write Address=%04x\n", addr); + + if (dev->board != NE2K_NE1000) { if ((addr >= DP8390_DWORD_MEMSTART) && (addr < DP8390_DWORD_MEMEND)) { dev->dp8390.mem[addr-DP8390_DWORD_MEMSTART] = val & 0xff; if ((len == 2) || (len == 4)) { @@ -444,6 +461,25 @@ asic_read(nic_t *dev, uint32_t off, unsigned int len) case 0x0f: /* Reset register */ nic_soft_reset(dev); break; + + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: + retval = 0; + break; default: nelog(3, "%s: ASIC read invalid address %04x\n", @@ -454,7 +490,6 @@ asic_read(nic_t *dev, uint32_t off, unsigned int len) return(retval); } - static void asic_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) { @@ -500,6 +535,24 @@ asic_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) /* end of reset pulse */ break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: + break; + default: /* this is invalid, but happens under win95 device detection */ nelog(3, "%s: ASIC write invalid address %04x, ignoring\n", dev->name, (unsigned)off); @@ -636,16 +689,6 @@ page0_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) { uint8_t val2; - /* It appears to be a common practice to use outw on page0 regs... */ - - /* break up outw into two outb's */ - if (len == 2) { - page0_write(dev, off, (val & 0xff), 1); - if (off < 0x0f) - page0_write(dev, off+1, ((val>>8)&0xff), 1); - return; - } - nelog(3, "%s: Page0 write to register 0x%02x, value=0x%02x\n", dev->name, off, val); @@ -1236,7 +1279,7 @@ write_cr(nic_t *dev, uint32_t val) dev->dp8390.ISR.rdma_done = 1; if (dev->dp8390.IMR.rdma_inte) { nic_interrupt(dev, 1); - if (! dev->is_pci) + if (!dev->is_pci) nic_interrupt(dev, 0); } } @@ -1251,11 +1294,11 @@ nic_read(nic_t *dev, uint32_t addr, unsigned len) nelog(3, "%s: read addr %x, len %d\n", dev->name, addr, len); - if (off >= 0x10) { - retval = asic_read(dev, off - 0x10, len); - } else if (off == 0x00) { + if (off >= 0x10) { + retval = asic_read(dev, off - 0x10, len); + } else if (off == 0x00) { retval = read_cr(dev); - } else switch(dev->dp8390.CR.pgsel) { + } else switch(dev->dp8390.CR.pgsel) { case 0x00: retval = page0_read(dev, off, len); break; @@ -1276,8 +1319,8 @@ nic_read(nic_t *dev, uint32_t addr, unsigned len) nelog(3, "%s: unknown value of pgsel in read - %d\n", dev->name, dev->dp8390.CR.pgsel); break; - } - + } + return(retval); } @@ -1315,15 +1358,15 @@ nic_write(nic_t *dev, uint32_t addr, uint32_t val, unsigned len) nelog(3, "%s: write addr %x, value %x len %d\n", dev->name, addr, val, len); - /* The high 16 bytes of i/o space are for the ne2000 asic - - the low 16 bytes are for the DS8390, with the current - page being selected by the PS0,PS1 registers in the - command register */ - if (off >= 0x10) { - asic_write(dev, off - 0x10, val, len); - } else if (off == 0x00) { + /* The high 16 bytes of i/o space are for the ne2000 asic - + the low 16 bytes are for the DS8390, with the current + page being selected by the PS0,PS1 registers in the + command register */ + if (off >= 0x10) { + asic_write(dev, off - 0x10, val, len); + } else if (off == 0x00) { write_cr(dev, val); - } else switch(dev->dp8390.CR.pgsel) { + } else switch(dev->dp8390.CR.pgsel) { case 0x00: page0_write(dev, off, val, len); break; @@ -1344,7 +1387,7 @@ nic_write(nic_t *dev, uint32_t addr, uint32_t val, unsigned len) nelog(3, "%s: unknown value of pgsel in write - %d\n", dev->name, dev->dp8390.CR.pgsel); break; - } + } } @@ -1698,32 +1741,43 @@ nic_iocheckremove(nic_t *dev, uint16_t addr) static void nic_ioset(nic_t *dev, uint16_t addr) { - if (dev->is_pci) { + if (dev->is_mca) { io_sethandler(addr, 16, - nic_readb, nic_readw, nic_readl, - nic_writeb, nic_writew, nic_writel, dev); + nic_readb, nic_readw, nic_readl, + nic_writeb, nic_writew, nic_writel, dev); io_sethandler(addr+16, 16, - nic_readb, nic_readw, nic_readl, - nic_writeb, nic_writew, nic_writel, dev); + nic_readb, nic_readw, nic_readl, + nic_writeb, nic_writew, nic_writel, dev); + io_sethandler(addr+0x1f, 16, + nic_readb, nic_readw, nic_readl, + nic_writeb, nic_writew, nic_writel, dev); + } + else if (dev->is_pci) { + io_sethandler(addr, 16, + nic_readb, nic_readw, nic_readl, + nic_writeb, nic_writew, nic_writel, dev); + io_sethandler(addr+16, 16, + nic_readb, nic_readw, nic_readl, + nic_writeb, nic_writew, nic_writel, dev); io_sethandler(addr+0x1f, 1, - nic_readb, nic_readw, nic_readl, - nic_writeb, nic_writew, nic_writel, dev); + nic_readb, nic_readw, nic_readl, + nic_writeb, nic_writew, nic_writel, dev); } else { io_sethandler(addr, 16, - nic_readb, NULL, NULL, - nic_writeb, NULL, NULL, dev); + nic_readb, NULL, NULL, + nic_writeb, NULL, NULL, dev); if (dev->is_8bit) { io_sethandler(addr+16, 16, - nic_readb, NULL, NULL, - nic_writeb, NULL, NULL, dev); + nic_readb, NULL, NULL, + nic_writeb, NULL, NULL, dev); } else { io_sethandler(addr+16, 16, - nic_readb, nic_readw, NULL, - nic_writeb, nic_writew, NULL, dev); + nic_readb, nic_readw, NULL, + nic_writeb, nic_writew, NULL, dev); } io_sethandler(addr+0x1f, 1, - nic_readb, NULL, NULL, - nic_writeb, NULL, NULL, dev); + nic_readb, NULL, NULL, + nic_writeb, NULL, NULL, dev); } } @@ -1731,7 +1785,18 @@ nic_ioset(nic_t *dev, uint16_t addr) static void nic_ioremove(nic_t *dev, uint16_t addr) { - if (dev->is_pci) { + if (dev->is_mca) { + io_removehandler(addr, 16, + nic_readb, nic_readw, nic_readl, + nic_writeb, nic_writew, nic_writel, dev); + io_removehandler(addr+16, 16, + nic_readb, nic_readw, nic_readl, + nic_writeb, nic_writew, nic_writel, dev); + io_removehandler(addr+0x1f, 16, + nic_readb, nic_readw, nic_readl, + nic_writeb, nic_writew, nic_writel, dev); + } + else if (dev->is_pci) { io_removehandler(addr, 16, nic_readb, nic_readw, nic_readl, nic_writeb, nic_writew, nic_writel, dev); @@ -2201,6 +2266,59 @@ nic_rom_init(nic_t *dev, wchar_t *s) dev->name, dev->bios_addr, dev->bios_size); } +static uint8_t +nic_mca_read(int port, void *priv) +{ + nic_t *dev = (nic_t *)priv; + + return(dev->pos_regs[port & 7]); +} + +#define MCA_7154_IO_PORTS { 0x1000, 0x2020, 0x8020, 0xa0a0, 0xb0b0, 0xc0c0, \ + 0xc3d0 } + +#define MCA_7154_IRQS { 3, 4, 5, 9 } + +static void +nic_mca_write(int port, uint8_t val, void *priv) +{ + nic_t *dev = (nic_t *)priv; + uint16_t novell_base[7] = MCA_7154_IO_PORTS; + int8_t novell_irq[4] = MCA_7154_IRQS; + + /* MCA does not write registers below 0x0100. */ + if (port < 0x0102) return; + + /* Save the MCA register value. */ + dev->pos_regs[port & 7] = val; + + nic_ioremove(dev, dev->base_address); + + /* This is always necessary so that the old handler doesn't remain. */ + /* Get the new assigned I/O base address. */ + dev->base_address = novell_base[((dev->pos_regs[2] & 0xE) >> 1) - 1]; + + /* Save the new IRQ values. */ + dev->base_irq = novell_irq[(dev->pos_regs[2] & 0x60) >> 5]; + + dev->bios_addr = 0x0000; + dev->has_bios = 0; + + /* + * The PS/2 Model 80 BIOS always enables a card if it finds one, + * even if no resources were assigned yet (because we only added + * the card, but have not run AutoConfig yet...) + * + * So, remove current address, if any. + */ + + /* Initialize the device if fully configured. */ + if (dev->pos_regs[2] & 0x01) { + /* Card enabled; register (new) I/O handler. */ + + nic_ioset(dev, dev->base_address); + } +} static void * nic_init(const device_t *info) @@ -2237,6 +2355,17 @@ nic_init(const device_t *info) dev->maclocal[2] = 0xD8; rom = (dev->board == NE2K_NE1000) ? NULL : ROM_PATH_NE2000; break; + + case NE2K_NE2_MCA: + pclog("NE/2 adapter\n"); + dev->is_mca = 1; + dev->maclocal[0] = 0x00; /* 00:00:D8 (Novell OID) */ + dev->maclocal[1] = 0x00; + dev->maclocal[2] = 0xD8; + dev->pos_regs[0] = 0x54; + dev->pos_regs[1] = 0x71; + rom = NULL; + break; case NE2K_RTL8019AS: case NE2K_RTL8029AS: @@ -2259,14 +2388,19 @@ nic_init(const device_t *info) dev->has_bios = 0; } } else { - dev->base_address = device_get_config_hex16("base"); - dev->base_irq = device_get_config_int("irq"); - if (dev->board == NE2K_NE2000) { - dev->bios_addr = device_get_config_hex20("bios_addr"); - dev->has_bios = !!dev->bios_addr; - } else { - dev->bios_addr = 0x00000; - dev->has_bios = 0; + if (dev->board != NE2K_NE2_MCA) { + dev->base_address = device_get_config_hex16("base"); + dev->base_irq = device_get_config_int("irq"); + if (dev->board == NE2K_NE2000) { + dev->bios_addr = device_get_config_hex20("bios_addr"); + dev->has_bios = !!dev->bios_addr; + } else { + dev->bios_addr = 0x00000; + dev->has_bios = 0; + } + } + else { + mca_add(nic_mca_read, nic_mca_write, dev); } } @@ -2277,7 +2411,7 @@ nic_init(const device_t *info) * Make this device known to the I/O system. * PnP and PCI devices start with address spaces inactive. */ - if (dev->board < NE2K_RTL8019AS) + if (dev->board < NE2K_RTL8019AS && dev->board != NE2K_NE2_MCA) nic_ioset(dev, dev->base_address); /* Set up our BIOS ROM space, if any. */ @@ -2439,7 +2573,7 @@ nic_init(const device_t *info) } /* Reset the board. */ - nic_reset(dev); + nic_reset(dev); /* Attach ourselves to the network module. */ network_attach(dev, dev->dp8390.physaddr, nic_rx); @@ -2504,15 +2638,18 @@ static const device_config_t ne1000_config[] = { "IRQ 3", 3 }, - { - "IRQ 4", 4 - }, { "IRQ 5", 5 }, { "IRQ 7", 7 }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, { "" } @@ -2563,9 +2700,6 @@ static const device_config_t ne2000_config[] = { "IRQ 3", 3 }, - { - "IRQ 4", 4 - }, { "IRQ 5", 5 }, @@ -2634,6 +2768,17 @@ static const device_config_t rtl8029as_config[] = } }; +static const device_config_t mca_mac_config[] = +{ + { + "mac", "MAC Address", CONFIG_MAC, "", -1 + }, + { + "", "", -1 + } +}; + + const device_t ne1000_device = { "Novell NE1000", @@ -2653,6 +2798,15 @@ const device_t ne2000_device = { ne2000_config }; +const device_t ne2_device = { + "Novell NE/2", + DEVICE_MCA, + NE2K_NE2_MCA, + nic_init, nic_close, NULL, + NULL, NULL, NULL, + mca_mac_config +}; + const device_t rtl8019as_device = { "Realtek RTL8019AS", DEVICE_ISA | DEVICE_AT, diff --git a/src/network/net_ne2000.h b/src/network/net_ne2000.h index 0453a3ba5..91905486f 100644 --- a/src/network/net_ne2000.h +++ b/src/network/net_ne2000.h @@ -38,15 +38,17 @@ enum { NE2K_NONE = 0, - NE2K_NE1000, /* 8-bit ISA NE1000 */ - NE2K_NE2000, /* 16-bit ISA NE2000 */ - NE2K_RTL8019AS, /* 16-bit ISA PnP Realtek 8019AS */ - NE2K_RTL8029AS /* 32-bit PCI Realtek 8029AS */ + NE2K_NE1000 = 1, /* 8-bit ISA NE1000 */ + NE2K_NE2000 = 2, /* 16-bit ISA NE2000 */ + NE2K_NE2_MCA = 3, /* 16-bit MCA NE/2 */ + NE2K_RTL8019AS = 4, /* 16-bit ISA PnP Realtek 8019AS */ + NE2K_RTL8029AS = 5 /* 32-bit PCI Realtek 8029AS */ }; extern const device_t ne1000_device; extern const device_t ne2000_device; +extern const device_t ne2_device; extern const device_t rtl8019as_device; extern const device_t rtl8029as_device; diff --git a/src/network/net_wd8003.c b/src/network/net_wd8003.c new file mode 100644 index 000000000..6830b17cb --- /dev/null +++ b/src/network/net_wd8003.c @@ -0,0 +1,1733 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Implementation of the following network controllers: + * - Novell NE1000 (ISA 8-bit); + * - Novell NE2000 (ISA 16-bit); + * - Realtek RTL8019AS (ISA 16-bit, PnP); + * - Realtek RTL8029AS (PCI). + * + * Version: @(#)net_ne2000.c 1.0.5 2018/07/11 + * + * Based on @(#)ne2k.cc v1.56.2.1 2004/02/02 22:37:22 cbothamy + * + * Authors: Fred N. van Kempen, + * TheCollector1995, + * Miran Grca, + * Peter Grehan, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Portions Copyright (C) 2002 MandrakeSoft S.A. + * + * This program 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. + * + * This program 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 this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../config.h" +#include "../machine/machine.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../mca.h" +#include "../pci.h" +#include "../pic.h" +#include "../random.h" +#include "../device.h" +#include "../ui.h" +#include "network.h" +#include "net_dp8390.h" +#include "net_wd8003.h" +#include "bswap.h" + +/* Board type codes in card ID */ +#define WE_TYPE_WD8003 0x01 +#define WE_TYPE_WD8003S 0x02 +#define WE_TYPE_WD8003E 0x03 +#define WE_TYPE_WD8013EBT 0x05 +#define WE_TYPE_TOSHIBA1 0x11 /* named PCETA1 */ +#define WE_TYPE_TOSHIBA2 0x12 /* named PCETA2 */ +#define WE_TYPE_TOSHIBA3 0x13 /* named PCETB */ +#define WE_TYPE_TOSHIBA4 0x14 /* named PCETC */ +#define WE_TYPE_WD8003W 0x24 +#define WE_TYPE_WD8003EB 0x25 +#define WE_TYPE_WD8013W 0x26 +#define WE_TYPE_WD8013EP 0x27 +#define WE_TYPE_WD8013WC 0x28 +#define WE_TYPE_WD8013EPC 0x29 +#define WE_TYPE_SMC8216T 0x2a +#define WE_TYPE_SMC8216C 0x2b +#define WE_TYPE_WD8013EBP 0x2c + +typedef struct { + dp8390_t dp8390; + mem_mapping_t ram_mapping; + uint32_t ram_addr, ram_size; + uint8_t macaddr[32]; /* ASIC ROM'd MAC address, even bytes */ + uint8_t maclocal[6]; /* configured MAC (local) address */ + int board; + const char *name; + uint32_t base_address; + int base_irq; + + /* POS registers, MCA boards only */ + uint8_t pos_regs[8]; + + /* Memory for WD cards*/ + uint8_t reg1; + uint8_t reg5; + uint8_t if_chip; + uint8_t board_chip; +} wd_t; + +static void wd_rx(void *, uint8_t *, int); +static void wd_tx(wd_t *, uint32_t); + +#ifdef ENABLE_WD_LOG +int wd_do_log = ENABLE_WD_LOG; +#endif + +static void +wdlog(int lvl, const char *fmt, ...) +{ +#ifdef ENABLE_WD_LOG + va_list ap; + + if (wd_do_log >= lvl) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + +static void +wd_interrupt(wd_t *dev, int set) +{ + if (set) + picint(1<base_irq); + else + picintc(1<base_irq); +} + +/* reset - restore state to power-up, cancelling all i/o */ +static void +wd_reset(void *priv) +{ + int i; + + wd_t *dev = (wd_t *)priv; + + wdlog(1, "%s: reset\n", dev->name); + + /* Initialize the MAC address area by doubling the physical address */ + dev->macaddr[0] = dev->dp8390.physaddr[0]; + dev->macaddr[1] = dev->dp8390.physaddr[1]; + dev->macaddr[2] = dev->dp8390.physaddr[2]; + dev->macaddr[3] = dev->dp8390.physaddr[3]; + dev->macaddr[4] = dev->dp8390.physaddr[4]; + dev->macaddr[5] = dev->dp8390.physaddr[5]; + + /* Zero out registers and memory */ + memset(&dev->dp8390.CR, 0x00, sizeof(dev->dp8390.CR) ); + memset(&dev->dp8390.ISR, 0x00, sizeof(dev->dp8390.ISR)); + memset(&dev->dp8390.IMR, 0x00, sizeof(dev->dp8390.IMR)); + memset(&dev->dp8390.DCR, 0x00, sizeof(dev->dp8390.DCR)); + memset(&dev->dp8390.TCR, 0x00, sizeof(dev->dp8390.TCR)); + memset(&dev->dp8390.TSR, 0x00, sizeof(dev->dp8390.TSR)); + memset(&dev->dp8390.RSR, 0x00, sizeof(dev->dp8390.RSR)); + dev->dp8390.tx_timer_active = 0; + dev->dp8390.local_dma = 0; + dev->dp8390.page_start = 0; + dev->dp8390.page_stop = 0; + dev->dp8390.bound_ptr = 0; + dev->dp8390.tx_page_start = 0; + dev->dp8390.num_coll = 0; + dev->dp8390.tx_bytes = 0; + dev->dp8390.fifo = 0; + dev->dp8390.remote_dma = 0; + dev->dp8390.remote_start = 0; + + dev->dp8390.remote_bytes = 0; + + dev->dp8390.tallycnt_0 = 0; + dev->dp8390.tallycnt_1 = 0; + dev->dp8390.tallycnt_2 = 0; + + dev->dp8390.curr_page = 0; + + dev->dp8390.rempkt_ptr = 0; + dev->dp8390.localpkt_ptr = 0; + dev->dp8390.address_cnt = 0; + + memset(&dev->dp8390.mem, 0x00, sizeof(dev->dp8390.mem)); + + /* Set power-up conditions */ + dev->dp8390.CR.stop = 1; + dev->dp8390.CR.rdma_cmd = 4; + dev->dp8390.ISR.reset = 1; + dev->dp8390.DCR.longaddr = 1; + + wd_interrupt(dev, 0); +} + +static uint32_t +wd_chipmem_read(wd_t *dev, uint32_t addr, unsigned int len) +{ + uint32_t retval = 0; + + if ((len == 2) && (addr & 0x1)) { + wdlog(3, "%s: unaligned chipmem word read\n", dev->name); + } + + /* ROM'd MAC address */ + if (dev->board == WD8003E) + { + if (addr <= 15) { + retval = dev->macaddr[addr % 16]; + if (len == 2) { + retval |= (dev->macaddr[(addr + 1) % 16] << 8); + } + return(retval); + } + } + + return(0xff); +} + +static uint32_t +wd_ram_read(uint32_t addr, unsigned len, void *priv) +{ + wd_t *dev = (wd_t *)priv; + uint32_t ret; + + if ((addr & 0x3fff) >= 0x2000) + { + if (len == 2) + return 0xffff; + else if (len == 1) + return 0xff; + else + return 0xffffffff; + } + + ret = dev->dp8390.mem[addr & 0x1fff]; + if (len == 2 || len == 4) + ret |= dev->dp8390.mem[(addr+1) & 0x1fff] << 8; + if (len == 4) { + ret |= dev->dp8390.mem[(addr+2) & 0x1fff] << 16; + ret |= dev->dp8390.mem[(addr+3) & 0x1fff] << 24; + } + + return ret; +} + +static uint8_t +wd_ram_readb(uint32_t addr, void *priv) +{ + wd_t *dev = (wd_t *)priv; + + return wd_ram_read(addr, 1, dev); +} + +static uint16_t +wd_ram_readw(uint32_t addr, void *priv) +{ + wd_t *dev = (wd_t *)priv; + + return wd_ram_read(addr, 2, dev); +} + +static uint32_t +wd_ram_readl(uint32_t addr, void *priv) +{ + wd_t *dev = (wd_t *)priv; + + return wd_ram_read(addr, 4, dev); +} + +static void +wd_ram_write(uint32_t addr, uint32_t val, unsigned len, void *priv) +{ + wd_t *dev = (wd_t *)priv; + + if ((addr & 0x3fff) >= 0x2000) + return; + + dev->dp8390.mem[addr & 0x1fff] = val & 0xff; + if (len == 2 || len == 4) + dev->dp8390.mem[(addr+1) & 0x1fff] = val >> 8; + if (len == 4) { + dev->dp8390.mem[(addr+2) & 0x1fff] = val >> 16; + dev->dp8390.mem[(addr+3) & 0x1fff] = val >> 24; + } +} + +static void +wd_ram_writeb(uint32_t addr, uint8_t val, void *priv) +{ + wd_t *dev = (wd_t *)priv; + + wd_ram_write(addr, val, 1, dev); +} + +static void +wd_ram_writew(uint32_t addr, uint16_t val, void *priv) +{ + wd_t *dev = (wd_t *)priv; + + wd_ram_write(addr, val, 2, dev); +} + +static void +wd_ram_writel(uint32_t addr, uint32_t val, void *priv) +{ + wd_t *dev = (wd_t *)priv; + + wd_ram_write(addr, val, 4, dev); +} + +static uint32_t +wd_smc_read(wd_t *dev, uint32_t off) +{ + uint32_t retval = 0; + uint32_t checksum = 0; + + switch(off) { + case 0x00: + break; + + case 0x01: + if (dev->board == WD8003E) + retval = dev->dp8390.physaddr[0]; + if (dev->board == WD8013EPA) + retval = dev->reg1; + break; + + case 0x02: + if (dev->board == WD8003E) + retval = dev->dp8390.physaddr[1]; + break; + + case 0x03: + if (dev->board == WD8003E) + retval = dev->dp8390.physaddr[2]; + break; + + case 0x04: + if (dev->board == WD8003E) + retval = dev->dp8390.physaddr[3]; + break; + + case 0x05: + if (dev->board == WD8003E) + retval = dev->dp8390.physaddr[4]; + if (dev->board == WD8013EPA) + retval = dev->reg5; + break; + + case 0x06: + if (dev->board == WD8003E) + retval = dev->dp8390.physaddr[5]; + break; + + case 0x07: + if (dev->board == WD8013EPA) + { + if (dev->if_chip != 0x35 && dev->if_chip != 0x3A) + { + retval = 0; + break; + } + + retval = dev->if_chip; + } + break; + + case 0x08: + retval = dev->dp8390.physaddr[0]; + break; + + case 0x09: + retval = dev->dp8390.physaddr[1]; + break; + + case 0x0a: + retval = dev->dp8390.physaddr[2]; + break; + + case 0x0b: + retval = dev->dp8390.physaddr[3]; + break; + + case 0x0c: + retval = dev->dp8390.physaddr[4]; + break; + + case 0x0d: + retval = dev->dp8390.physaddr[5]; + break; + + case 0x0e: + retval = dev->board_chip; + break; + + case 0x0f: + { + /*This has to return the byte that adds up to 0xFF*/ + checksum = (dev->dp8390.physaddr[0] + dev->dp8390.physaddr[1] + dev->dp8390.physaddr[2] + + dev->dp8390.physaddr[3] + dev->dp8390.physaddr[4] + dev->dp8390.physaddr[5] + + dev->board_chip); + + retval = 0xff - (checksum & 0xff); + } + break; + } + + wdlog(2, "%s: ASIC read addr=0x%02x, value=0x%04x\n", + dev->name, (unsigned)off, (unsigned) retval); + + return(retval); +} + +static void +wd_smc_write(wd_t *dev, uint32_t off, uint32_t val) +{ + wdlog(2, "%s: ASIC write addr=0x%02x, value=0x%04x\n", + dev->name, (unsigned)off, (unsigned) val); + + switch(off) { + case 0x00: /* WD Control register */ + if (val & 0x80) + { + dev->dp8390.ISR.reset = 1; + return; + } + + mem_mapping_disable(&dev->ram_mapping); + + if (val & 0x40) + { + mem_mapping_enable(&dev->ram_mapping); + } + break; + + case 0x01: + dev->reg1 = val; + break; + + case 0x04: + break; + + case 0x05: + dev->reg5 = val; + break; + + case 0x06: + break; + + case 0x07: + dev->if_chip = val; + break; + + default: /* this is invalid, but happens under win95 device detection */ + wdlog(3, "%s: ASIC write invalid address %04x, ignoring\n", + dev->name, (unsigned)off); + break; + } +} + + +/* Handle reads/writes to the 'zeroth' page of the DS8390 register file. */ +static uint8_t +page0_read(wd_t *dev, uint32_t off) +{ + uint8_t retval = 0; + + switch(off) { + case 0x01: /* CLDA0 */ + retval = (dev->dp8390.local_dma & 0xff); + break; + + case 0x02: /* CLDA1 */ + retval = (dev->dp8390.local_dma >> 8); + break; + + case 0x03: /* BNRY */ + retval = dev->dp8390.bound_ptr; + break; + + case 0x04: /* TSR */ + retval = ((dev->dp8390.TSR.ow_coll << 7) | + (dev->dp8390.TSR.cd_hbeat << 6) | + (dev->dp8390.TSR.fifo_ur << 5) | + (dev->dp8390.TSR.no_carrier << 4) | + (dev->dp8390.TSR.aborted << 3) | + (dev->dp8390.TSR.collided << 2) | + (dev->dp8390.TSR.tx_ok)); + break; + + case 0x05: /* NCR */ + retval = dev->dp8390.num_coll; + break; + + case 0x06: /* FIFO */ + /* reading FIFO is only valid in loopback mode */ + wdlog(3, "%s: reading FIFO not supported yet\n", dev->name); + retval = dev->dp8390.fifo; + break; + + case 0x07: /* ISR */ + retval = ((dev->dp8390.ISR.reset << 7) | + (dev->dp8390.ISR.rdma_done << 6) | + (dev->dp8390.ISR.cnt_oflow << 5) | + (dev->dp8390.ISR.overwrite << 4) | + (dev->dp8390.ISR.tx_err << 3) | + (dev->dp8390.ISR.rx_err << 2) | + (dev->dp8390.ISR.pkt_tx << 1) | + (dev->dp8390.ISR.pkt_rx)); + break; + + case 0x08: /* CRDA0 */ + retval = (dev->dp8390.remote_dma & 0xff); + break; + + case 0x09: /* CRDA1 */ + retval = (dev->dp8390.remote_dma >> 8); + break; + + case 0x0a: /* reserved / RTL8029ID0 */ + wdlog(3, "%s: reserved Page0 read - 0x0a\n", dev->name); + retval = 0xff; + break; + + case 0x0b: /* reserved / RTL8029ID1 */ + wdlog(3, "%s: reserved Page0 read - 0x0b\n", dev->name); + retval = 0xff; + break; + + case 0x0c: /* RSR */ + retval = ((dev->dp8390.RSR.deferred << 7) | + (dev->dp8390.RSR.rx_disabled << 6) | + (dev->dp8390.RSR.rx_mbit << 5) | + (dev->dp8390.RSR.rx_missed << 4) | + (dev->dp8390.RSR.fifo_or << 3) | + (dev->dp8390.RSR.bad_falign << 2) | + (dev->dp8390.RSR.bad_crc << 1) | + (dev->dp8390.RSR.rx_ok)); + break; + + case 0x0d: /* CNTR0 */ + retval = dev->dp8390.tallycnt_0; + break; + + case 0x0e: /* CNTR1 */ + retval = dev->dp8390.tallycnt_1; + break; + + case 0x0f: /* CNTR2 */ + retval = dev->dp8390.tallycnt_2; + break; + + default: + wdlog(3, "%s: Page0 register 0x%02x out of range\n", + dev->name, off); + break; + } + + wdlog(3, "%s: Page0 read from register 0x%02x, value=0x%02x\n", + dev->name, off, retval); + + return(retval); +} + + +static void +page0_write(wd_t *dev, uint32_t off, uint8_t val) +{ + uint8_t val2; + + wdlog(3, "%s: Page0 write to register 0x%02x, value=0x%02x\n", + dev->name, off, val); + + switch(off) { + case 0x01: /* PSTART */ + dev->dp8390.page_start = val; + break; + + case 0x02: /* PSTOP */ + dev->dp8390.page_stop = val; + break; + + case 0x03: /* BNRY */ + dev->dp8390.bound_ptr = val; + break; + + case 0x04: /* TPSR */ + dev->dp8390.tx_page_start = val; + break; + + case 0x05: /* TBCR0 */ + /* Clear out low byte and re-insert */ + dev->dp8390.tx_bytes &= 0xff00; + dev->dp8390.tx_bytes |= (val & 0xff); + break; + + case 0x06: /* TBCR1 */ + /* Clear out high byte and re-insert */ + dev->dp8390.tx_bytes &= 0x00ff; + dev->dp8390.tx_bytes |= ((val & 0xff) << 8); + break; + + case 0x07: /* ISR */ + val &= 0x7f; /* clear RST bit - status-only bit */ + /* All other values are cleared iff the ISR bit is 1 */ + dev->dp8390.ISR.pkt_rx &= !((int)((val & 0x01) == 0x01)); + dev->dp8390.ISR.pkt_tx &= !((int)((val & 0x02) == 0x02)); + dev->dp8390.ISR.rx_err &= !((int)((val & 0x04) == 0x04)); + dev->dp8390.ISR.tx_err &= !((int)((val & 0x08) == 0x08)); + dev->dp8390.ISR.overwrite &= !((int)((val & 0x10) == 0x10)); + dev->dp8390.ISR.cnt_oflow &= !((int)((val & 0x20) == 0x20)); + dev->dp8390.ISR.rdma_done &= !((int)((val & 0x40) == 0x40)); + val = ((dev->dp8390.ISR.rdma_done << 6) | + (dev->dp8390.ISR.cnt_oflow << 5) | + (dev->dp8390.ISR.overwrite << 4) | + (dev->dp8390.ISR.tx_err << 3) | + (dev->dp8390.ISR.rx_err << 2) | + (dev->dp8390.ISR.pkt_tx << 1) | + (dev->dp8390.ISR.pkt_rx)); + val &= ((dev->dp8390.IMR.rdma_inte << 6) | + (dev->dp8390.IMR.cofl_inte << 5) | + (dev->dp8390.IMR.overw_inte << 4) | + (dev->dp8390.IMR.txerr_inte << 3) | + (dev->dp8390.IMR.rxerr_inte << 2) | + (dev->dp8390.IMR.tx_inte << 1) | + (dev->dp8390.IMR.rx_inte)); + if (val == 0x00) + wd_interrupt(dev, 0); + break; + + case 0x08: /* RSAR0 */ + /* Clear out low byte and re-insert */ + dev->dp8390.remote_start &= 0xff00; + dev->dp8390.remote_start |= (val & 0xff); + dev->dp8390.remote_dma = dev->dp8390.remote_start; + break; + + case 0x09: /* RSAR1 */ + /* Clear out high byte and re-insert */ + dev->dp8390.remote_start &= 0x00ff; + dev->dp8390.remote_start |= ((val & 0xff) << 8); + dev->dp8390.remote_dma = dev->dp8390.remote_start; + break; + + case 0x0a: /* RBCR0 */ + /* Clear out low byte and re-insert */ + dev->dp8390.remote_bytes &= 0xff00; + dev->dp8390.remote_bytes |= (val & 0xff); + break; + + case 0x0b: /* RBCR1 */ + /* Clear out high byte and re-insert */ + dev->dp8390.remote_bytes &= 0x00ff; + dev->dp8390.remote_bytes |= ((val & 0xff) << 8); + break; + + case 0x0c: /* RCR */ + /* Check if the reserved bits are set */ + if (val & 0xc0) { + wdlog(3, "%s: RCR write, reserved bits set\n", + dev->name); + } + + /* Set all other bit-fields */ + dev->dp8390.RCR.errors_ok = ((val & 0x01) == 0x01); + dev->dp8390.RCR.runts_ok = ((val & 0x02) == 0x02); + dev->dp8390.RCR.broadcast = ((val & 0x04) == 0x04); + dev->dp8390.RCR.multicast = ((val & 0x08) == 0x08); + dev->dp8390.RCR.promisc = ((val & 0x10) == 0x10); + dev->dp8390.RCR.monitor = ((val & 0x20) == 0x20); + + /* Monitor bit is a little suspicious... */ + if (val & 0x20) wdlog(3, "%s: RCR write, monitor bit set!\n", + dev->name); + break; + + case 0x0d: /* TCR */ + /* Check reserved bits */ + if (val & 0xe0) wdlog(3, "%s: TCR write, reserved bits set\n", + dev->name); + + /* Test loop mode (not supported) */ + if (val & 0x06) { + dev->dp8390.TCR.loop_cntl = (val & 0x6) >> 1; + wdlog(3, "%s: TCR write, loop mode %d not supported\n", + dev->name, dev->dp8390.TCR.loop_cntl); + } + else { + dev->dp8390.TCR.loop_cntl = 0; + } + + /* Inhibit-CRC not supported. */ + if (val & 0x01) wdlog(3, + "%s: TCR write, inhibit-CRC not supported\n",dev->name); + + /* Auto-transmit disable very suspicious */ + if (val & 0x08) + { + wdlog(3, + "%s: TCR write, auto transmit disable not supported\n", + dev->name); + } + + /* Allow collision-offset to be set, although not used */ + dev->dp8390.TCR.coll_prio = ((val & 0x08) == 0x08); + break; + + case 0x0e: /* DCR */ + /* the loopback mode is not suppported yet */ + if (! (val & 0x08)) wdlog(3, + "%s: DCR write, loopback mode selected\n", dev->name); + + /* It is questionable to set longaddr and auto_rx, since + * they are not supported on the NE2000. Print a warning + * and continue. */ + if (val & 0x04) + wdlog(3, "%s: DCR write - LAS set ???\n", dev->name); + if (val & 0x10) + wdlog(3, "%s: DCR write - AR set ???\n", dev->name); + + /* Set other values. */ + dev->dp8390.DCR.wdsize = ((val & 0x01) == 0x01); + dev->dp8390.DCR.endian = ((val & 0x02) == 0x02); + dev->dp8390.DCR.longaddr = ((val & 0x04) == 0x04); /* illegal ? */ + dev->dp8390.DCR.loop = ((val & 0x08) == 0x08); + dev->dp8390.DCR.auto_rx = ((val & 0x10) == 0x10); /* also illegal ? */ + dev->dp8390.DCR.fifo_size = (val & 0x50) >> 5; + break; + + case 0x0f: /* IMR */ + /* Check for reserved bit */ + if (val & 0x80) + wdlog(3, "%s: IMR write, reserved bit set\n",dev->name); + + /* Set other values */ + dev->dp8390.IMR.rx_inte = ((val & 0x01) == 0x01); + dev->dp8390.IMR.tx_inte = ((val & 0x02) == 0x02); + dev->dp8390.IMR.rxerr_inte = ((val & 0x04) == 0x04); + dev->dp8390.IMR.txerr_inte = ((val & 0x08) == 0x08); + dev->dp8390.IMR.overw_inte = ((val & 0x10) == 0x10); + dev->dp8390.IMR.cofl_inte = ((val & 0x20) == 0x20); + dev->dp8390.IMR.rdma_inte = ((val & 0x40) == 0x40); + val2 = ((dev->dp8390.ISR.rdma_done << 6) | + (dev->dp8390.ISR.cnt_oflow << 5) | + (dev->dp8390.ISR.overwrite << 4) | + (dev->dp8390.ISR.tx_err << 3) | + (dev->dp8390.ISR.rx_err << 2) | + (dev->dp8390.ISR.pkt_tx << 1) | + (dev->dp8390.ISR.pkt_rx)); + if (((val & val2) & 0x7f) == 0) + wd_interrupt(dev, 0); + else + wd_interrupt(dev, 1); + break; + + default: + wdlog(3, "%s: Page0 write, bad register 0x%02x\n", + dev->name, off); + break; + } +} + +/* Handle reads/writes to the first page of the DS8390 register file. */ +static uint8_t +page1_read(wd_t *dev, uint32_t off) +{ + wdlog(3, "%s: Page1 read from register 0x%02x\n", + dev->name, off); + + switch(off) { + case 0x01: /* PAR0-5 */ + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + return(dev->dp8390.physaddr[off - 1]); + + case 0x07: /* CURR */ + wdlog(3, "%s: returning current page: 0x%02x\n", + dev->name, (dev->dp8390.curr_page)); + return(dev->dp8390.curr_page); + + case 0x08: /* MAR0-7 */ + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + return(dev->dp8390.mchash[off - 8]); + + default: + wdlog(3, "%s: Page1 read register 0x%02x out of range\n", + dev->name, off); + return(0); + } +} + + +static void +page1_write(wd_t *dev, uint32_t off, uint8_t val) +{ + wdlog(3, "%s: Page1 write to register 0x%02x, value=0x%04x\n", + dev->name, off, val); + + switch(off) { + case 0x01: /* PAR0-5 */ + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + dev->dp8390.physaddr[off - 1] = val; + if (off == 6) wdlog(3, + "%s: physical address set to %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, + dev->dp8390.physaddr[0], dev->dp8390.physaddr[1], + dev->dp8390.physaddr[2], dev->dp8390.physaddr[3], + dev->dp8390.physaddr[4], dev->dp8390.physaddr[5]); + break; + + case 0x07: /* CURR */ + dev->dp8390.curr_page = val; + break; + + case 0x08: /* MAR0-7 */ + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + dev->dp8390.mchash[off - 8] = val; + break; + + default: + wdlog(3, "%s: Page1 write register 0x%02x out of range\n", + dev->name, off); + break; + } +} + +/* Handle reads/writes to the second page of the DS8390 register file. */ +static uint8_t +page2_read(wd_t *dev, uint32_t off) +{ + wdlog(3, "%s: Page2 read from register 0x%02x\n", + dev->name, off); + + switch(off) { + case 0x01: /* PSTART */ + return(dev->dp8390.page_start); + + case 0x02: /* PSTOP */ + return(dev->dp8390.page_stop); + + case 0x03: /* Remote Next-packet pointer */ + return(dev->dp8390.rempkt_ptr); + + case 0x04: /* TPSR */ + return(dev->dp8390.tx_page_start); + + case 0x05: /* Local Next-packet pointer */ + return(dev->dp8390.localpkt_ptr); + + case 0x06: /* Address counter (upper) */ + return(dev->dp8390.address_cnt >> 8); + + case 0x07: /* Address counter (lower) */ + return(dev->dp8390.address_cnt & 0xff); + + case 0x08: /* Reserved */ + case 0x09: + case 0x0a: + case 0x0b: + wdlog(3, "%s: reserved Page2 read - register 0x%02x\n", + dev->name, off); + return(0xff); + + case 0x0c: /* RCR */ + return ((dev->dp8390.RCR.monitor << 5) | + (dev->dp8390.RCR.promisc << 4) | + (dev->dp8390.RCR.multicast << 3) | + (dev->dp8390.RCR.broadcast << 2) | + (dev->dp8390.RCR.runts_ok << 1) | + (dev->dp8390.RCR.errors_ok)); + + case 0x0d: /* TCR */ + return ((dev->dp8390.TCR.coll_prio << 4) | + (dev->dp8390.TCR.ext_stoptx << 3) | + ((dev->dp8390.TCR.loop_cntl & 0x3) << 1) | + (dev->dp8390.TCR.crc_disable)); + + case 0x0e: /* DCR */ + return (((dev->dp8390.DCR.fifo_size & 0x3) << 5) | + (dev->dp8390.DCR.auto_rx << 4) | + (dev->dp8390.DCR.loop << 3) | + (dev->dp8390.DCR.longaddr << 2) | + (dev->dp8390.DCR.endian << 1) | + (dev->dp8390.DCR.wdsize)); + + case 0x0f: /* IMR */ + return ((dev->dp8390.IMR.rdma_inte << 6) | + (dev->dp8390.IMR.cofl_inte << 5) | + (dev->dp8390.IMR.overw_inte << 4) | + (dev->dp8390.IMR.txerr_inte << 3) | + (dev->dp8390.IMR.rxerr_inte << 2) | + (dev->dp8390.IMR.tx_inte << 1) | + (dev->dp8390.IMR.rx_inte)); + + default: + wdlog(3, "%s: Page2 register 0x%02x out of range\n", + dev->name, off); + break; + } + + return(0); +} + + +static void +page2_write(wd_t *dev, uint32_t off, uint8_t val) +{ +/* Maybe all writes here should be BX_PANIC()'d, since they + affect internal operation, but let them through for now + and print a warning. */ + wdlog(3, "%s: Page2 write to register 0x%02x, value=0x%04x\n", + dev->name, off, val); + switch(off) { + case 0x01: /* CLDA0 */ + /* Clear out low byte and re-insert */ + dev->dp8390.local_dma &= 0xff00; + dev->dp8390.local_dma |= (val & 0xff); + break; + + case 0x02: /* CLDA1 */ + /* Clear out high byte and re-insert */ + dev->dp8390.local_dma &= 0x00ff; + dev->dp8390.local_dma |= ((val & 0xff) << 8); + break; + + case 0x03: /* Remote Next-pkt pointer */ + dev->dp8390.rempkt_ptr = val; + break; + + case 0x04: + wdlog(3, "page 2 write to reserved register 0x04\n"); + break; + + case 0x05: /* Local Next-packet pointer */ + dev->dp8390.localpkt_ptr = val; + break; + + case 0x06: /* Address counter (upper) */ + /* Clear out high byte and re-insert */ + dev->dp8390.address_cnt &= 0x00ff; + dev->dp8390.address_cnt |= ((val & 0xff) << 8); + break; + + case 0x07: /* Address counter (lower) */ + /* Clear out low byte and re-insert */ + dev->dp8390.address_cnt &= 0xff00; + dev->dp8390.address_cnt |= (val & 0xff); + break; + + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + wdlog(3, "%s: Page2 write to reserved register 0x%02x\n", + dev->name, off); + break; + + default: + wdlog(3, "%s: Page2 write, illegal register 0x%02x\n", + dev->name, off); + break; + } +} + +/* Routines for handling reads/writes to the Command Register. */ +static uint8_t +read_cr(wd_t *dev) +{ + uint32_t retval; + + retval = (((dev->dp8390.CR.pgsel & 0x03) << 6) | + ((dev->dp8390.CR.rdma_cmd & 0x07) << 3) | + (dev->dp8390.CR.tx_packet << 2) | + (dev->dp8390.CR.start << 1) | + (dev->dp8390.CR.stop)); + wdlog(3, "%s: read CR returns 0x%02x\n", dev->name, retval); + + return(retval); +} + +static void +write_cr(wd_t *dev, uint8_t val) +{ + wdlog(3, "%s: wrote 0x%02x to CR, CS=%08x, PC=%08x\n", dev->name, val, CS, cpu_state.pc); + + /* Validate remote-DMA */ + if ((val & 0x38) == 0x00) { + wdlog(3, "%s: CR write - invalid rDMA value 0\n", dev->name); + val |= 0x20; /* dma_cmd == 4 is a safe default */ + } + + /* Check for s/w reset */ + if (val & 0x01) { + dev->dp8390.ISR.reset = 1; + dev->dp8390.CR.stop = 1; + } else { + dev->dp8390.CR.stop = 0; + } + + dev->dp8390.CR.rdma_cmd = (val & 0x38) >> 3; + + /* If start command issued, the RST bit in the ISR */ + /* must be cleared */ + if ((val & 0x02) && !dev->dp8390.CR.start) + dev->dp8390.ISR.reset = 0; + + dev->dp8390.CR.start = ((val & 0x02) == 0x02); + dev->dp8390.CR.pgsel = (val & 0xc0) >> 6; + + /* Check for send-packet command */ + if (dev->dp8390.CR.rdma_cmd == 3) { + /* Set up DMA read from receive ring */ + dev->dp8390.remote_start = dev->dp8390.remote_dma = dev->dp8390.bound_ptr * 256; + dev->dp8390.remote_bytes = (uint16_t) wd_chipmem_read(dev, dev->dp8390.bound_ptr * 256 + 2, 2); + wdlog(2, "%s: sending buffer #x%x length %d\n", + dev->name, dev->dp8390.remote_start, dev->dp8390.remote_bytes); + } + + /* Check for start-tx */ + if ((val & 0x04) && dev->dp8390.TCR.loop_cntl) { + if (dev->dp8390.TCR.loop_cntl) { + wd_rx(dev, &dev->dp8390.mem[dev->dp8390.tx_page_start*256 - DP8390_WORD_MEMSTART], + dev->dp8390.tx_bytes); + } + } else if (val & 0x04) { + if (dev->dp8390.CR.stop) { + if (dev->dp8390.tx_bytes == 0) /* njh@bandsman.co.uk */ { + return; /* Solaris9 probe */ + } + wdlog(3, "%s: CR write - tx start, dev in reset\n", dev->name); + } + + if (dev->dp8390.tx_bytes == 0) + wdlog(3, "%s: CR write - tx start, tx bytes == 0\n", dev->name); + + /* Send the packet to the system driver */ + dev->dp8390.CR.tx_packet = 1; + + network_tx(dev->dp8390.mem, dev->dp8390.tx_bytes); + + wd_tx(dev, val); + } + + /* Linux probes for an interrupt by setting up a remote-DMA read + * of 0 bytes with remote-DMA completion interrupts enabled. + * Detect this here */ + if (dev->dp8390.CR.rdma_cmd == 0x01 && dev->dp8390.CR.start && dev->dp8390.remote_bytes == 0) { + dev->dp8390.ISR.rdma_done = 1; + if (dev->dp8390.IMR.rdma_inte) { + wd_interrupt(dev, 1); + wd_interrupt(dev, 0); + } + } +} + +static uint8_t +wd_readb(uint16_t addr, void *priv) +{ + wd_t *dev = (wd_t *)priv; + + uint8_t retval = 0; + int off = addr - dev->base_address; + + wdlog(3, "%s: read addr %x\n", dev->name, addr); + + if (off == 0x10) + { + retval = read_cr(dev); + } + else if (off >= 0x00 && off <= 0x0f) + { + retval = wd_smc_read(dev, off); + } + else + { + switch(dev->dp8390.CR.pgsel) { + case 0x00: + retval = page0_read(dev, off - 0x10); + break; + + case 0x01: + retval = page1_read(dev, off - 0x10); + break; + + case 0x02: + retval = page2_read(dev, off - 0x10); + break; + + default: + wdlog(3, "%s: unknown value of pgsel in read - %d\n", + dev->name, dev->dp8390.CR.pgsel); + break; + } + } + + return(retval); +} + + +static void +wd_writeb(uint16_t addr, uint8_t val, void *priv) +{ + wd_t *dev = (wd_t *)priv; + int off = addr - dev->base_address; + + wdlog(3, "%s: write addr %x, value %x\n", dev->name, addr, val); + + if (off == 0x10) + { + write_cr(dev, val); + } + else if (off >= 0x00 && off <= 0x0f) + { + wd_smc_write(dev, off, val); + } + else + { + switch(dev->dp8390.CR.pgsel) { + case 0x00: + page0_write(dev, off - 0x10, val); + break; + + case 0x01: + page1_write(dev, off - 0x10, val); + break; + + default: + wdlog(3, "%s: unknown value of pgsel in write - %d\n", + dev->name, dev->dp8390.CR.pgsel); + break; + } + } +} + +static void wd_ioset(wd_t *dev, uint16_t addr); +static void wd_ioremove(wd_t *dev, uint16_t addr); + +static void +wd_ioset(wd_t *dev, uint16_t addr) +{ + io_sethandler(addr, 0x20, + wd_readb, NULL, NULL, + wd_writeb, NULL, NULL, dev); +} + +static void +wd_ioremove(wd_t *dev, uint16_t addr) +{ + io_removehandler(addr, 0x20, + wd_readb, NULL, NULL, + wd_writeb, NULL, NULL, dev); +} + +/* + * Called by the platform-specific code when an Ethernet frame + * has been received. The destination address is tested to see + * if it should be accepted, and if the RX ring has enough room, + * it is copied into it and the receive process is updated. + */ +static void +wd_rx(void *priv, uint8_t *buf, int io_len) +{ + static uint8_t bcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; + wd_t *dev = (wd_t *)priv; + uint8_t pkthdr[4]; + uint8_t *startptr; + int pages, avail; + int idx, nextpage; + int endbytes; + + //FIXME: move to upper layer + ui_sb_update_icon(SB_NETWORK, 1); + + if (io_len != 60) + wdlog(2, "%s: rx_frame with length %d\n", dev->name, io_len); + + if ((dev->dp8390.CR.stop != 0) || (dev->dp8390.page_start == 0)) return; + + /* + * Add the pkt header + CRC to the length, and work + * out how many 256-byte pages the frame would occupy. + */ + pages = (io_len + sizeof(pkthdr) + sizeof(uint32_t) + 255)/256; + if (dev->dp8390.curr_page < dev->dp8390.bound_ptr) { + avail = dev->dp8390.bound_ptr - dev->dp8390.curr_page; + } else { + avail = (dev->dp8390.page_stop - dev->dp8390.page_start) - + (dev->dp8390.curr_page - dev->dp8390.bound_ptr); + } + + /* + * Avoid getting into a buffer overflow condition by + * not attempting to do partial receives. The emulation + * to handle this condition seems particularly painful. + */ + if ((avail < pages) +#if NE2K_NEVER_FULL_RING + || (avail == pages) +#endif + ) { + wdlog(1, "%s: no space\n", dev->name); + + //FIXME: move to upper layer + ui_sb_update_icon(SB_NETWORK, 0); + return; + } + + if ((io_len < 40/*60*/) && !dev->dp8390.RCR.runts_ok) { + wdlog(1, "%s: rejected small packet, length %d\n", dev->name, io_len); + + //FIXME: move to upper layer + ui_sb_update_icon(SB_NETWORK, 0); + return; + } + + /* Some computers don't care... */ + if (io_len < 60) + io_len = 60; + + wdlog(2, "%s: RX %x:%x:%x:%x:%x:%x > %x:%x:%x:%x:%x:%x len %d\n", + dev->name, + buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], + io_len); + + /* Do address filtering if not in promiscuous mode. */ + if (! dev->dp8390.RCR.promisc) { + /* If this is a broadcast frame.. */ + if (! memcmp(buf, bcast_addr, 6)) { + /* Broadcast not enabled, we're done. */ + if (! dev->dp8390.RCR.broadcast) { + wdlog(2, "%s: RX BC disabled\n", dev->name); + + //FIXME: move to upper layer + ui_sb_update_icon(SB_NETWORK, 0); + return; + } + } + + /* If this is a multicast frame.. */ + else if (buf[0] & 0x01) { + /* Multicast not enabled, we're done. */ + if (! dev->dp8390.RCR.multicast) { +#if 1 + wdlog(2, "%s: RX MC disabled\n", dev->name); +#endif + + //FIXME: move to upper layer + ui_sb_update_icon(SB_NETWORK, 0); + return; + } + + /* Are we listening to this multicast address? */ + idx = mcast_index(buf); + if (! (dev->dp8390.mchash[idx>>3] & (1<<(idx&0x7)))) { + wdlog(2, "%s: RX MC not listed\n", dev->name); + + //FIXME: move to upper layer + ui_sb_update_icon(SB_NETWORK, 0); + return; + } + } + + /* Unicast, must be for us.. */ + else if (memcmp(buf, dev->dp8390.physaddr, 6)) return; + } else { + wdlog(2, "%s: RX promiscuous receive\n", dev->name); + } + + nextpage = dev->dp8390.curr_page + pages; + if (nextpage >= dev->dp8390.page_stop) + nextpage -= (dev->dp8390.page_stop - dev->dp8390.page_start); + + /* Set up packet header. */ + pkthdr[0] = 0x01; /* RXOK - packet is OK */ + pkthdr[1] = nextpage; /* ptr to next packet */ + pkthdr[2] = (io_len + sizeof(pkthdr))&0xff; /* length-low */ + pkthdr[3] = (io_len + sizeof(pkthdr))>>8; /* length-hi */ + wdlog(2, "%s: RX pkthdr [%02x %02x %02x %02x]\n", + dev->name, pkthdr[0], pkthdr[1], pkthdr[2], pkthdr[3]); + + /* Copy into buffer, update curpage, and signal interrupt if config'd */ + startptr = dev->dp8390.mem + (dev->dp8390.curr_page * 256); + memcpy(startptr, pkthdr, sizeof(pkthdr)); + if ((nextpage > dev->dp8390.curr_page) || + ((dev->dp8390.curr_page + pages) == dev->dp8390.page_stop)) { + memcpy(startptr+sizeof(pkthdr), buf, io_len); + } else { + endbytes = (dev->dp8390.page_stop - dev->dp8390.curr_page) * 256; + memcpy(startptr+sizeof(pkthdr), buf, endbytes-sizeof(pkthdr)); + startptr = dev->dp8390.mem + (dev->dp8390.page_start * 256); + memcpy(startptr, buf+endbytes-sizeof(pkthdr), io_len-endbytes+8); + } + dev->dp8390.curr_page = nextpage; + + dev->dp8390.RSR.rx_ok = 1; + dev->dp8390.RSR.rx_mbit = (buf[0] & 0x01) ? 1 : 0; + dev->dp8390.ISR.pkt_rx = 1; + + if (dev->dp8390.IMR.rx_inte) + wd_interrupt(dev, 1); + + //FIXME: move to upper layer + ui_sb_update_icon(SB_NETWORK, 0); +} + +static void +wd_tx(wd_t *dev, uint32_t val) +{ + dev->dp8390.CR.tx_packet = 0; + dev->dp8390.TSR.tx_ok = 1; + dev->dp8390.ISR.pkt_tx = 1; + + /* Generate an interrupt if not masked */ + if (dev->dp8390.IMR.tx_inte) + wd_interrupt(dev, 1); + dev->dp8390.tx_timer_active = 0; +} + +static uint8_t +wd_mca_read(int port, void *priv) +{ + wd_t *dev = (wd_t *)priv; + + return(dev->pos_regs[port & 7]); +} + +#define MCA_61C8_IRQS { 3, 4, 10, 15 } + +static void +wd_mca_write(int port, uint8_t val, void *priv) +{ + wd_t *dev = (wd_t *)priv; + int8_t irq[4] = MCA_61C8_IRQS; + uint32_t ram_size = 0; + + /* MCA does not write registers below 0x0100. */ + if (port < 0x0102) return; + + /* Save the MCA register value. */ + dev->pos_regs[port & 7] = val; + + wd_ioremove(dev, dev->base_address); + + dev->base_address = 0x800 + (((dev->pos_regs[2] & 0xf0) >> 4) * 0x1000); + + dev->ram_addr = 0xC0000 + ((dev->pos_regs[3] & 0x0f) * 0x2000) + ((dev->pos_regs[3] & 0x80) ? 0xF00000 : 0); + + dev->base_irq = irq[(dev->pos_regs[5] & 0x0c) >> 2]; + + ram_size = (dev->pos_regs[3] & 0x10) ? 0x4000 : 0x2000; + + /* + * The PS/2 Model 80 BIOS always enables a card if it finds one, + * even if no resources were assigned yet (because we only added + * the card, but have not run AutoConfig yet...) + * + * So, remove current address, if any. + */ + + /* Initialize the device if fully configured. */ + if (dev->pos_regs[2] & 0x01) { + /* Card enabled; register (new) I/O handler. */ + + wd_ioset(dev, dev->base_address); + + wd_reset(dev); + + mem_mapping_add(&dev->ram_mapping, dev->ram_addr, ram_size, + wd_ram_readb, wd_ram_readw, wd_ram_readl, + wd_ram_writeb, wd_ram_writew, wd_ram_writel, + NULL, MEM_MAPPING_EXTERNAL, dev); + + mem_mapping_disable(&dev->ram_mapping); + + wdlog(1, "%s: attached IO=0x%X IRQ=%d, RAM addr=0x%06x\n", dev->name, + dev->base_address, dev->base_irq, dev->ram_addr); + } +} + +static void * +wd_init(const device_t *info) +{ + uint32_t mac; + wd_t *dev; +#ifdef ENABLE_NIC_LOG + int i; +#endif + + /* Get the desired debug level. */ +#ifdef ENABLE_NIC_LOG + i = device_get_config_int("debug"); + if (i > 0) wd_do_log = i; +#endif + + dev = malloc(sizeof(wd_t)); + memset(dev, 0x00, sizeof(wd_t)); + dev->name = info->name; + dev->board = info->local; + + switch(dev->board) { + case WD8003E: + dev->board_chip = WE_TYPE_WD8003E; + dev->maclocal[0] = 0x00; /* 00:00:C0 (WD/SMC OID) */ + dev->maclocal[1] = 0x00; + dev->maclocal[2] = 0xC0; + break; + + case WD8013EBT: + dev->board_chip = WE_TYPE_WD8013EBT; + dev->maclocal[0] = 0x00; /* 00:00:C0 (WD/SMC OID) */ + dev->maclocal[1] = 0x00; + dev->maclocal[2] = 0xC0; + break; + + case WD8013EPA: + dev->board_chip = WE_TYPE_WD8013EP | 0x80; + dev->maclocal[0] = 0x00; /* 00:00:C0 (WD/SMC OID) */ + dev->maclocal[1] = 0x00; + dev->maclocal[2] = 0xC0; + dev->pos_regs[0] = 0xC8; + dev->pos_regs[1] = 0x61; + break; + } + + if (dev->board != WD8013EPA) { + dev->base_address = device_get_config_hex16("base"); + dev->base_irq = device_get_config_int("irq"); + dev->ram_addr = device_get_config_hex20("ram_addr"); + } + else { + mca_add(wd_mca_read, wd_mca_write, dev); + } + + /* See if we have a local MAC address configured. */ + mac = device_get_config_mac("mac", -1); + + /* + * Make this device known to the I/O system. + * PnP and PCI devices start with address spaces inactive. + */ + if (dev->board != WD8013EPA) + wd_ioset(dev, dev->base_address); + + /* Set up our BIA. */ + if (mac & 0xff000000) { + /* Generate new local MAC. */ + dev->maclocal[3] = random_generate(); + dev->maclocal[4] = random_generate(); + dev->maclocal[5] = random_generate(); + mac = (((int) dev->maclocal[3]) << 16); + mac |= (((int) dev->maclocal[4]) << 8); + mac |= ((int) dev->maclocal[5]); + device_set_config_mac("mac", mac); + } else { + dev->maclocal[3] = (mac>>16) & 0xff; + dev->maclocal[4] = (mac>>8) & 0xff; + dev->maclocal[5] = (mac & 0xff); + } + memcpy(dev->dp8390.physaddr, dev->maclocal, sizeof(dev->maclocal)); + + wdlog(0, "%s: I/O=%04x, IRQ=%d, MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, dev->base_address, dev->base_irq, + dev->dp8390.physaddr[0], dev->dp8390.physaddr[1], dev->dp8390.physaddr[2], + dev->dp8390.physaddr[3], dev->dp8390.physaddr[4], dev->dp8390.physaddr[5]); + + /* Reset the board. */ + if (dev->board != WD8013EPA) + wd_reset(dev); + + /* Attach ourselves to the network module. */ + network_attach(dev, dev->dp8390.physaddr, wd_rx); + + /* Map this system into the memory map. */ + if (dev->board != WD8013EPA) + { + mem_mapping_add(&dev->ram_mapping, dev->ram_addr, 0x4000, + wd_ram_readb, NULL, NULL, + wd_ram_writeb, NULL, NULL, + NULL, MEM_MAPPING_EXTERNAL, dev); + mem_mapping_disable(&dev->ram_mapping); + + wdlog(1, "%s: attached IO=0x%X IRQ=%d, RAM addr=0x%06x\n", dev->name, + dev->base_address, dev->base_irq, dev->ram_addr); + } + + return(dev); +} + + +static void +wd_close(void *priv) +{ + wd_t *dev = (wd_t *)priv; + + /* Make sure the platform layer is shut down. */ + network_close(); + + wd_ioremove(dev, dev->base_address); + + wdlog(1, "%s: closed\n", dev->name); + + free(dev); +} + +static const device_config_t wd8003_config[] = +{ + { + "base", "Address", CONFIG_HEX16, "", 0x300, + { + { + "0x240", 0x240 + }, + { + "0x280", 0x280 + }, + { + "0x300", 0x300 + }, + { + "0x380", 0x380 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 3, + { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "" + } + }, + }, + { + "mac", "MAC Address", CONFIG_MAC, "", -1 + }, + { + "ram_addr", "RAM address", CONFIG_HEX20, "", 0xD0000, + { + { + "C800", 0xC8000 + }, + { + "CC00", 0xCC000 + }, + { + "D000", 0xD0000 + }, + { + "D400", 0xD4000 + }, + { + "D800", 0xD8000 + }, + { + "DC00", 0xDC000 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +static const device_config_t wd8013_config[] = +{ + { + "base", "Address", CONFIG_HEX16, "", 0x300, + { + { + "0x240", 0x240 + }, + { + "0x280", 0x280 + }, + { + "0x300", 0x300 + }, + { + "0x380", 0x380 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 3, + { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "IRQ 15", 15 + }, + { + "" + } + }, + }, + { + "mac", "MAC Address", CONFIG_MAC, "", -1 + }, + { + "ram_addr", "RAM address", CONFIG_HEX20, "", 0xD0000, + { + { + "C800", 0xC8000 + }, + { + "CC00", 0xCC000 + }, + { + "D000", 0xD0000 + }, + { + "D400", 0xD4000 + }, + { + "D800", 0xD8000 + }, + { + "DC00", 0xDC000 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +static const device_config_t mca_mac_config[] = +{ + { + "mac", "MAC Address", CONFIG_MAC, "", -1 + }, + { + "", "", -1 + } +}; + +const device_t wd8003e_device = { + "Western Digital WD8003E", + DEVICE_ISA, + WD8003E, + wd_init, wd_close, NULL, + NULL, NULL, NULL, + wd8003_config +}; + +const device_t wd8013ebt_device = { + "Western Digital WD8013EBT", + DEVICE_ISA, + WD8013EBT, + wd_init, wd_close, NULL, + NULL, NULL, NULL, + wd8013_config +}; + +const device_t wd8013epa_device = { + "Western Digital WD8013EP/A", + DEVICE_MCA, + WD8013EPA, + wd_init, wd_close, NULL, + NULL, NULL, NULL, + mca_mac_config +}; \ No newline at end of file diff --git a/src/network/net_wd8003.h b/src/network/net_wd8003.h new file mode 100644 index 000000000..a9a1e3c32 --- /dev/null +++ b/src/network/net_wd8003.h @@ -0,0 +1,49 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Definitions for the NE2000 ethernet controller. + * + * Version: @(#)net_ne2000.h 1.0.2 2018/03/15 + * + * Authors: Fred N. van Kempen, + * + * Copyright 2017,2018 Fred N. van Kempen. + * + * This program 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. + * + * This program 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 this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#ifndef NET_WD8003_H +# define NET_WD8003_H + +enum { + WD_NONE = 0, + WD8003E = 1, /* 8-bit ISA WD8003E */ + WD8013EBT = 2, /* 16-bit ISA WD8013EBT */ + WD8013EPA = 3 /* MCA WD8013EP/A */ +}; + +extern const device_t wd8003e_device; +extern const device_t wd8013ebt_device; +extern const device_t wd8013epa_device; + +#endif /*NET_WD8003_H*/ \ No newline at end of file diff --git a/src/network/network.c b/src/network/network.c index 107ffef6c..8f20a4299 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -62,6 +62,7 @@ #include "network.h" #include "net_3c503.h" #include "net_ne2000.h" +#include "net_wd8003.h" static netcard_t net_cards[] = { @@ -75,6 +76,14 @@ static netcard_t net_cards[] = { NULL }, { "[ISA] Realtek RTL8019AS", "ne2kpnp", &rtl8019as_device, NULL }, + { "[ISA] Western Digital WD8003E","wd8003e", &wd8003e_device, + NULL }, + { "[ISA] Western Digital WD8013EBT","wd8013ebt", &wd8013ebt_device, + NULL }, + { "[MCA] Novell NE/2", "ne2", &ne2_device, + NULL }, + { "[MCA] Western Digital WD8013EP/A","wd8013epa", &wd8013epa_device, + NULL }, { "[PCI] Realtek RTL8029AS", "ne2kpci", &rtl8029as_device, NULL }, { "", "", NULL, diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c index e67407cd9..958e23514 100644 --- a/src/scsi/scsi_ncr5380.c +++ b/src/scsi/scsi_ncr5380.c @@ -9,7 +9,7 @@ * Implementation of the NCR 5380 series of SCSI Host Adapters * made by NCR. These controllers were designed for the ISA bus. * - * Version: @(#)scsi_ncr5380.c 1.0.15 2018/06/13 + * Version: @(#)scsi_ncr5380.c 1.0.16 2018/07/02 * * Authors: Sarah Walker, * TheCollector1995, @@ -19,6 +19,7 @@ * Copyright 2017,2018 TheCollector1995. * Copyright 2017,2018 Fred N. van Kempen. */ +#include #include #include #include @@ -63,11 +64,6 @@ #define NCR_DMAINIRECV 7 /* DMA initiator receive (write only) */ #define NCR_RESETPARITY 7 /* reset parity/interrupt (read only) */ -#define POLL_TIME_US 10LL -#define MAX_BYTES_TRANSFERRED_PER_POLL 50 -/*10us poll period with 50 bytes transferred per poll = 5MB/sec*/ - - #define ICR_DBP 0x01 #define ICR_ATN 0x02 #define ICR_SEL 0x04 @@ -83,6 +79,7 @@ #define STATUS_ACK 0x01 #define STATUS_BUSY_ERROR 0x04 +#define STATUS_PHASE_MATCH 0x08 #define STATUS_INT 0x10 #define STATUS_DRQ 0x40 #define STATUS_END_OF_DMA 0x80 @@ -93,10 +90,9 @@ #define TCR_REQ 0x08 #define TCR_LAST_BYTE_SENT 0x80 -#define CTRL_DATA_DIR (1<<6) -#define STATUS_BUFFER_NOT_READY (1<<2) -#define STATUS_53C80_ACCESSIBLE (1<<7) - +#define CTRL_DATA_DIR 0x40 +#define STATUS_BUFFER_NOT_READY 0x04 +#define STATUS_53C80_ACCESSIBLE 0x80 typedef struct { uint8_t icr; @@ -106,16 +102,23 @@ typedef struct { uint8_t isr; uint8_t output_data; - int target_bsy; - int target_req; uint8_t target_id; - uint8_t bus_status; - int dma_mode; - - scsi_bus_t bus; -} ncr5380_t; + + int bus_host, cur_bus, bus_in; + int new_phase; + int state; + + int clear_req, wait_data, wait_complete; + + int command_pos; + uint8_t command[20]; + int data_pos; + uint8_t tx_data; + + uint8_t unk_08, unk_08_ret; +} ncr_t; typedef struct { const char *name; @@ -132,30 +135,41 @@ typedef struct { uint8_t status_ctrl; - uint8_t buffer[0x80]; - int buffer_pos; - int buffer_host_pos; + uint8_t buffer[128]; + int buffer_pos; + int buffer_host_pos; uint8_t int_ram[0x40]; - uint8_t ext_ram[0x600]; + uint8_t ext_ram[0x600]; + + ncr_t ncr; + + int dma_enabled; - ncr5380_t ncr; - int ncr5380_dma_enabled; + int64_t timer_period; + int64_t timer_enabled; - int64_t dma_timer; - int64_t dma_enabled; + int64_t media_period; + int64_t temp_period; - int ncr_busy; -} ncr_t; + int ncr_busy; + double period; + + int is_non_data_mode; +} ncr5380_t; -enum { - DMA_IDLE = 0, - DMA_SEND, - DMA_TARGET_RECEIVE, - DMA_INITIATOR_RECEIVE -}; +#define STATE_IDLE 0 +#define STATE_COMMAND 1 +#define STATE_DATAIN 2 +#define STATE_DATAOUT 3 +#define STATE_STATUS 4 +#define STATE_MESSAGEIN 5 +#define STATE_SELECT 6 +#define DMA_IDLE 0 +#define DMA_SEND 1 +#define DMA_INITIATOR_RECEIVE 2 #ifdef ENABLE_NCR5380_LOG int ncr5380_do_log = ENABLE_NCR5380_LOG; @@ -176,94 +190,211 @@ ncr_log(const char *fmt, ...) #endif } +#define SET_BUS_STATE(ncr, state) ncr->cur_bus = (ncr->cur_bus & ~(SCSI_PHASE_MESSAGE_IN)) | (state & (SCSI_PHASE_MESSAGE_IN)) static void -dma_changed(void *priv, int mode, int enable) +ncr_callback(void *priv); + +static int +get_dev_id(uint8_t data) { - ncr_t *scsi = (ncr_t *)priv; + int c; - scsi->ncr5380_dma_enabled = (mode && enable); + for (c = 0; c < SCSI_ID_MAX; c++) { + if (data & (1 << c)) return(c); + } - scsi->dma_enabled = (scsi->ncr5380_dma_enabled && scsi->block_count_loaded); + return(-1); } - -void -ncr5380_reset(ncr5380_t *ncr) +/* get the length of a SCSI command based on its command byte type */ +static int +get_cmd_len(int cbyte) { - memset(ncr, 0x00, sizeof(ncr5380_t)); + int len; + int group; + + group = (cbyte>>5) & 7; + + if (group == 0) len = 6; + if (group == 1 || group == 2) len = 10; + + return(len); } +static void +ncr_reset(ncr_t *ncr) +{ + memset(ncr, 0x00, sizeof(ncr_t)); + ncr_log("NCR reset\n"); +} static uint32_t -get_bus_host(ncr5380_t *ncr) +get_bus_host(ncr_t *ncr) { uint32_t bus_host = 0; if (ncr->icr & ICR_DBP) - bus_host |= BUS_DBP; + { + ncr_log("Data bus phase\n"); + bus_host |= BUS_DBP; + } if (ncr->icr & ICR_SEL) - bus_host |= BUS_SEL; - if (ncr->icr & ICR_ATN) - bus_host |= BUS_ATN; + { + ncr_log("Selection phase\n"); + bus_host |= BUS_SEL; + } if (ncr->tcr & TCR_IO) - bus_host |= BUS_IO; + { + ncr_log("Data phase\n"); + bus_host |= BUS_IO; + } if (ncr->tcr & TCR_CD) - bus_host |= BUS_CD; + { + ncr_log("Command phase\n"); + bus_host |= BUS_CD; + } if (ncr->tcr & TCR_MSG) - bus_host |= BUS_MSG; + { + ncr_log("Message phase\n"); + bus_host |= BUS_MSG; + } if (ncr->tcr & TCR_REQ) - bus_host |= BUS_REQ; + { + ncr_log("Request phase\n"); + bus_host |= BUS_REQ; + } if (ncr->icr & ICR_BSY) - bus_host |= BUS_BSY; - if (ncr->icr & ICR_ACK) - bus_host |= BUS_ACK; - if (ncr->mode & MODE_ARBITRATE) - bus_host |= BUS_ARB; + { + ncr_log("Busy phase\n"); + bus_host |= BUS_BSY; + } + if (ncr->icr & ICR_ATN) + { + bus_host |= BUS_ATN; + } + if (ncr->icr & ICR_ACK) + { + ncr_log("ACK phase\n"); + bus_host |= BUS_ACK; + } + if (ncr->mode & MODE_ARBITRATE) + { + bus_host |= BUS_ARB; + } return(bus_host | BUS_SETDATA(ncr->output_data)); } +static void +ncr_wait_process(ncr5380_t *ncr_dev) +{ + ncr_t *ncr = &ncr_dev->ncr; + + /*Wait processes to handle bus requests*/ + ncr_log("Clear REQ=%d\n", ncr->clear_req); + if (ncr->clear_req) + { + ncr->clear_req--; + if (!ncr->clear_req) + { + ncr_log("Prelude to command data\n"); + SET_BUS_STATE(ncr, ncr->new_phase); + ncr->cur_bus |= BUS_REQ; + } + } + + if (ncr->wait_data) + { + ncr->wait_data--; + if (!ncr->wait_data) + { + scsi_device_t *dev; + + dev = &SCSIDevices[ncr->target_id]; + SET_BUS_STATE(ncr, ncr->new_phase); + + if (ncr->new_phase == SCSI_PHASE_DATA_IN) + { + ncr_log("Data In bus phase\n"); + ncr->tx_data = dev->CmdBuffer[ncr->data_pos++]; + ncr->state = STATE_DATAIN; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP; + } + else if (ncr->new_phase == SCSI_PHASE_STATUS) + { + ncr_log("Status bus phase\n"); + ncr->cur_bus |= BUS_REQ; + ncr->state = STATE_STATUS; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(dev->Status) | BUS_DBP; + } + else if (ncr->new_phase == SCSI_PHASE_MESSAGE_IN) + { + ncr_log("Message In bus phase\n"); + ncr->state = STATE_MESSAGEIN; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(0) | BUS_DBP; + } + else + { + if (ncr->new_phase & BUS_IDLE) { + ncr_log("Bus Idle phase\n"); + ncr->state = STATE_IDLE; + ncr->cur_bus &= ~BUS_BSY; + ncr_dev->media_period = 0LL; + ncr_dev->temp_period = 0LL; + } else { + ncr->state = STATE_DATAOUT; + ncr_log("Data Out bus phase\n"); + } + } + } + } + + if (ncr->wait_complete) + { + ncr->wait_complete--; + if (!ncr->wait_complete) + { + ncr->cur_bus |= BUS_REQ; + } + } + + ncr->bus_host = ncr->cur_bus; +} static void ncr_write(uint16_t port, uint8_t val, void *priv) { - ncr_t *scsi = (ncr_t *)priv; - ncr5380_t *ncr = &scsi->ncr; - int bus_host = 0; + ncr5380_t *ncr_dev = (ncr5380_t *)priv; + ncr_t *ncr = &ncr_dev->ncr; + + ncr_log("NCR5380 write(%04x,%02x) @%04X:%04X\n",port & 7,val,CS,cpu_state.pc); -#if ENABLE_NCR5380_LOG - ncr_log("NCR5380 write(%04x,%02x) @%04X:%04X\n",port,val,CS,cpu_state.pc); -#endif switch (port & 7) { case 0: /* Output data register */ + ncr_log("Write: Output data register\n"); ncr->output_data = val; break; case 1: /* Initiator Command Register */ - if ((val & (ICR_BSY | ICR_SEL)) == (ICR_BSY | ICR_SEL) && - (ncr->icr & (ICR_BSY | ICR_SEL)) == ICR_SEL) { - uint8_t temp = ncr->output_data & 0x7f; - - ncr->target_id = -1; - while (temp) { - temp >>= 1; - ncr->target_id++; - } - - ncr_log("Select - target ID = %i, temp data %x\n", ncr->target_id, temp); - } + ncr_log("Write: Initiator command register\n"); ncr->icr = val; + + ncr_dev->timer_enabled = 1; break; case 2: /* Mode register */ + ncr_log("Write: Mode register, val=%02x\n", val & MODE_DMA); if ((val & MODE_ARBITRATE) && !(ncr->mode & MODE_ARBITRATE)) { ncr->icr &= ~ICR_ARB_LOST; ncr->icr |= ICR_ARB_IN_PROGRESS; } + ncr->mode = val; - dma_changed(scsi, ncr->dma_mode, ncr->mode & MODE_DMA); - if (! (ncr->mode & MODE_DMA)) { + + /*If it's not DMA mode, don't do anything*/ + if (!(ncr->mode & MODE_DMA)) { + ncr_log("No DMA mode\n"); ncr->tcr &= ~TCR_LAST_BYTE_SENT; ncr->isr &= ~STATUS_END_OF_DMA; ncr->dma_mode = DMA_IDLE; @@ -271,103 +402,133 @@ ncr_write(uint16_t port, uint8_t val, void *priv) break; case 3: /* Target Command Register */ + ncr_log("Write: Target Command register\n"); ncr->tcr = val; break; case 4: /* Select Enable Register */ - ncr->ser = val; + ncr_log("Write: Select Enable register\n"); break; - + case 5: /* start DMA Send */ + ncr_log("Write: start DMA send register\n"); + ncr_log("Write 6 or 10, block count loaded=%d\n", ncr_dev->block_count_loaded); + /*a Write 6/10 has occurred, start the timer when the block count is loaded*/ ncr->dma_mode = DMA_SEND; - dma_changed(scsi, ncr->dma_mode, ncr->mode & MODE_DMA); break; case 7: /* start DMA Initiator Receive */ + ncr_log("Write: start DMA initiator receive register\n"); + ncr_log("Read 6 or 10, block count loaded=%d\n", ncr_dev->block_count_loaded); + /*a Read 6/10 has occurred, start the timer when the block count is loaded*/ ncr->dma_mode = DMA_INITIATOR_RECEIVE; - dma_changed(scsi, ncr->dma_mode, ncr->mode & MODE_DMA); break; default: -#if 1 ncr_log("NCR5380: bad write %04x %02x\n", port, val); -#endif break; } - - bus_host = get_bus_host(ncr); - - scsi_bus_update(&ncr->bus, bus_host); } - static uint8_t ncr_read(uint16_t port, void *priv) { - ncr_t *scsi = (ncr_t *)priv; - ncr5380_t *ncr = &scsi->ncr; - uint32_t bus = 0; + ncr5380_t *ncr_dev = (ncr5380_t *)priv; + ncr_t *ncr = &ncr_dev->ncr; uint8_t ret = 0xff; switch (port & 7) { - case 0: /* current SCSI data */ + case 0: /* Current SCSI data */ + ncr_log("Read: Current SCSI data register\n"); if (ncr->icr & ICR_DBP) { + /*Return the data from the output register if on data bus phase from ICR*/ + ncr_log("Data Bus Phase\n"); ret = ncr->output_data; - } else { - bus = scsi_bus_read(&ncr->bus); - ret = BUS_GETDATA(bus); + } else { + /*Return the data from the SCSI bus*/ + ncr_wait_process(ncr_dev); + ncr_log("NCR GetData=%02x\n", BUS_GETDATA(ncr->bus_host)); + ret = BUS_GETDATA(ncr->bus_host); } break; case 1: /* Initiator Command Register */ + ncr_log("Read: Initiator Command register\n"); + ncr_log("NCR ICR Read=%02x\n", ncr->icr); + ret = ncr->icr; break; case 2: /* Mode register */ + ncr_log("Read: Mode register\n"); ret = ncr->mode; break; case 3: /* Target Command Register */ + ncr_log("Read: Target Command register\n"); + ncr_log("NCR target stat=%02x\n", ncr->tcr); ret = ncr->tcr; break; case 4: /* Current SCSI Bus status */ + ncr_log("Read: SCSI bus status register\n"); ret = 0; - bus = scsi_bus_read(&ncr->bus); - ret |= (bus & 0xff); + ncr_wait_process(ncr_dev); + ncr_log("NCR cur bus stat=%02x\n", ncr->bus_host & 0xff); + ret |= (ncr->bus_host & 0xff); break; case 5: /* Bus and Status register */ - ret = 0; + ncr_log("Read: Bus and Status register\n"); + ret = 0; - bus = get_bus_host(ncr); - if (scsi_bus_match(&ncr->bus, bus)) - ret |= 0x08; - bus = scsi_bus_read(&ncr->bus); - - if (bus & BUS_ACK) - ret |= STATUS_ACK; - if ((bus & BUS_REQ) && (ncr->mode & MODE_DMA)) - ret |= STATUS_DRQ; - if ((bus & BUS_REQ) && (ncr->mode & MODE_DMA)) { - int bus_state = 0; - - if (bus & BUS_IO) - bus_state |= TCR_IO; - if (bus & BUS_CD) - bus_state |= TCR_CD; - if (bus & BUS_MSG) - bus_state |= TCR_MSG; - if ((ncr->tcr & 7) != bus_state) - ncr->isr |= STATUS_INT; + ncr->bus_host = get_bus_host(ncr); + ncr_log("Get host from Interrupt\n"); + + /*Check if the phase in process matches with TCR's*/ + if ((ncr->bus_host & SCSI_PHASE_MESSAGE_IN) == + (ncr->cur_bus & SCSI_PHASE_MESSAGE_IN)) + { + ncr_log("Phase match\n"); + ret |= STATUS_PHASE_MATCH; + } + else + picint(1 << ncr_dev->irq); + + ncr_wait_process(ncr_dev); + + if (ncr->bus_host & BUS_ACK) + ret |= STATUS_ACK; + + if ((ncr->bus_host & BUS_REQ) && (ncr->mode & MODE_DMA)) { + ncr_log("Entering DMA mode\n"); + ret |= STATUS_DRQ; + + int bus = 0; + + if (ncr->bus_host & BUS_IO) + bus |= TCR_IO; + if (ncr->bus_host & BUS_CD) + bus |= TCR_CD; + if (ncr->bus_host & BUS_MSG) + bus |= TCR_MSG; + if ((ncr->tcr & 7) != bus) + { + ncr->isr |= STATUS_INT; + } + } + if (!(ncr->bus_host & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) + { + ncr_log("Busy error\n"); + ret |= STATUS_BUSY_ERROR; } - if (!(bus & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) - ret |= STATUS_BUSY_ERROR; ret |= (ncr->isr & (STATUS_INT | STATUS_END_OF_DMA)); break; case 7: /* reset Parity/Interrupt */ ncr->isr &= ~STATUS_INT; + picintc(1 << ncr_dev->irq); + ncr_log("Reset IRQ\n"); break; default: @@ -375,198 +536,76 @@ ncr_read(uint16_t port, void *priv) break; } -#if ENABLE_NCR5380_LOG - ncr_log("NCR5380 read(%04x)=%02x @%04X:%04X\n", port, ret, CS,cpu_state.pc); -#endif + ncr_log("NCR5380 read(%04x)=%02x @%04X:%04X\n", port & 7, ret, CS,cpu_state.pc); + return(ret); } - -static void -dma_callback(void *priv) -{ - ncr_t *scsi = (ncr_t *)priv; - ncr5380_t *ncr = &scsi->ncr; - int bytes_transferred = 0; - int c; - - scsi->dma_timer += POLL_TIME_US * TIMER_USEC; - - switch (scsi->ncr.dma_mode) { - case DMA_SEND: - if (scsi->status_ctrl & CTRL_DATA_DIR) { - ncr_log("DMA_SEND with DMA direction set wrong\n"); - break; - } - - if (!(scsi->status_ctrl & STATUS_BUFFER_NOT_READY)) { - break; - } - - if (! scsi->block_count_loaded) break; - - while (bytes_transferred < MAX_BYTES_TRANSFERRED_PER_POLL) { - int bus; - uint8_t data; - - for (c = 0; c < 10; c++) { - uint8_t status = scsi_bus_read(&ncr->bus); - - if (status & BUS_REQ) break; - } - if (c == 10) break; - - /* Data ready. */ - data = scsi->buffer[scsi->buffer_pos]; - bus = get_bus_host(ncr) & ~BUS_DATAMASK; - bus |= BUS_SETDATA(data); - - scsi_bus_update(&ncr->bus, bus | BUS_ACK); - scsi_bus_update(&ncr->bus, bus & ~BUS_ACK); - - bytes_transferred++; - if (++scsi->buffer_pos == 128) { - scsi->buffer_pos = 0; - scsi->buffer_host_pos = 0; - scsi->status_ctrl &= ~STATUS_BUFFER_NOT_READY; - scsi->block_count = (scsi->block_count - 1) & 255; - scsi->ncr_busy = 0; - if (! scsi->block_count) { - scsi->block_count_loaded = 0; - scsi->dma_enabled = 0; - - ncr->tcr |= TCR_LAST_BYTE_SENT; - ncr->isr |= STATUS_END_OF_DMA; - if (ncr->mode & MODE_ENA_EOP_INT) - ncr->isr |= STATUS_INT; - } - break; - } - } - break; - - case DMA_INITIATOR_RECEIVE: - if (!(scsi->status_ctrl & CTRL_DATA_DIR)) { - ncr_log("DMA_INITIATOR_RECEIVE with DMA direction set wrong\n"); - break; - } - - if (!(scsi->status_ctrl & STATUS_BUFFER_NOT_READY)) break; - - if (!scsi->block_count_loaded) break; - - while (bytes_transferred < MAX_BYTES_TRANSFERRED_PER_POLL) { - int bus; - uint8_t temp; - - for (c = 0; c < 10; c++) { - uint8_t status = scsi_bus_read(&ncr->bus); - - if (status & BUS_REQ) break; - } - if (c == 10) break; - - /* Data ready. */ - bus = scsi_bus_read(&ncr->bus); - temp = BUS_GETDATA(bus); - bus = get_bus_host(ncr); - - scsi_bus_update(&ncr->bus, bus | BUS_ACK); - scsi_bus_update(&ncr->bus, bus & ~BUS_ACK); - - bytes_transferred++; - scsi->buffer[scsi->buffer_pos++] = temp; - if (scsi->buffer_pos == 128) { - scsi->buffer_pos = 0; - scsi->buffer_host_pos = 0; - scsi->status_ctrl &= ~STATUS_BUFFER_NOT_READY; - scsi->block_count = (scsi->block_count - 1) & 255; - if (!scsi->block_count) { - scsi->block_count_loaded = 0; - scsi->dma_enabled = 0; - - ncr->isr |= STATUS_END_OF_DMA; - if (ncr->mode & MODE_ENA_EOP_INT) - ncr->isr |= STATUS_INT; - } - break; - } - } - break; - - default: -#if 1 - ncr_log("DMA callback bad mode %i\n", scsi->ncr.dma_mode); -#endif - break; - } - - c = scsi_bus_read(&ncr->bus); - if (!(c & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) { - ncr->mode &= ~MODE_DMA; - ncr->dma_mode = DMA_IDLE; - dma_changed(scsi, ncr->dma_mode, ncr->mode & MODE_DMA); - } -} - - /* Memory-mapped I/O READ handler. */ static uint8_t memio_read(uint32_t addr, void *priv) { - ncr_t *scsi = (ncr_t *)priv; + ncr5380_t *ncr_dev = (ncr5380_t *)priv; uint8_t ret = 0xff; - + addr &= 0x3fff; #if ENABLE_NCR5380_LOG ncr_log("memio_read %08x\n", addr); #endif if (addr < 0x2000) - ret = scsi->bios_rom.rom[addr & 0x1fff]; + ret = ncr_dev->bios_rom.rom[addr & 0x1fff]; else if (addr < 0x3800) ret = 0xff; else if (addr >= 0x3a00) - ret = scsi->ext_ram[addr - 0x3a00]; + ret = ncr_dev->ext_ram[addr - 0x3a00]; else switch (addr & 0x3f80) { case 0x3800: #if ENABLE_NCR5380_LOG - ncr_log("Read intRAM %02x %02x\n", addr & 0x3f, scsi->int_ram[addr & 0x3f]); + ncr_log("Read intRAM %02x %02x\n", addr & 0x3f, ncr_dev->int_ram[addr & 0x3f]); #endif - ret = scsi->int_ram[addr & 0x3f]; + ret = ncr_dev->int_ram[addr & 0x3f]; break; case 0x3880: #if ENABLE_NCR5380_LOG ncr_log("Read 53c80 %04x\n", addr); #endif - ret = ncr_read(addr, scsi); + ret = ncr_read(addr, ncr_dev); break; - + case 0x3900: -#if ENABLE_NCR5380_LOG - ncr_log(" Read 3900 %i %02x\n", scsi->buffer_host_pos, scsi->status_ctrl); -#endif - if (scsi->buffer_host_pos >= 128 || !(scsi->status_ctrl & CTRL_DATA_DIR)) + ncr_log("Read 3900 host pos %i status ctrl %02x\n", ncr_dev->buffer_host_pos, ncr_dev->status_ctrl); + ncr_log("Read port 0x3900-0x397f\n"); + + if (ncr_dev->buffer_host_pos >= 128 || !(ncr_dev->status_ctrl & CTRL_DATA_DIR)) ret = 0xff; else { - ret = scsi->buffer[scsi->buffer_host_pos++]; + ret = ncr_dev->buffer[ncr_dev->buffer_host_pos++]; + + ncr_log("Read host buffer=%d\n", ncr_dev->buffer_host_pos); - if (scsi->buffer_host_pos == 128) - scsi->status_ctrl |= STATUS_BUFFER_NOT_READY; + if (ncr_dev->buffer_host_pos == 128) + { + ncr_log("Not ready\n"); + ncr_dev->status_ctrl |= STATUS_BUFFER_NOT_READY; + } } break; case 0x3980: switch (addr) { case 0x3980: /* status */ - ret = scsi->status_ctrl;// | 0x80; - if (! scsi->ncr_busy) + ret = ncr_dev->status_ctrl;// | 0x80; + ncr_log("NCR status ctrl read=%02x\n", ncr_dev->status_ctrl & STATUS_BUFFER_NOT_READY); + if (!ncr_dev->ncr_busy) + { ret |= STATUS_53C80_ACCESSIBLE; + } break; case 0x3981: /* block counter register*/ - ret = scsi->block_count; + ret = ncr_dev->block_count; break; case 0x3982: /* switch register read */ @@ -577,7 +616,7 @@ memio_read(uint32_t addr, void *priv) ret = 0xff; break; } - break; + break; } #if ENABLE_NCR5380_LOG @@ -593,37 +632,37 @@ memio_read(uint32_t addr, void *priv) static void memio_write(uint32_t addr, uint8_t val, void *priv) { - ncr_t *scsi = (ncr_t *)priv; - + ncr5380_t *ncr_dev = (ncr5380_t *)priv; + addr &= 0x3fff; -#if ENABLE_NCR5380_LOG - ncr_log("memio_write(%08x,%02x) @%04X:%04X %i %02x\n", addr, val, CS,cpu_state.pc, scsi->buffer_host_pos, scsi->status_ctrl); -#endif + ncr_log("memio_write(%08x,%02x) @%04X:%04X %i %02x\n", addr, val, CS,cpu_state.pc, ncr_dev->buffer_host_pos, ncr_dev->status_ctrl); if (addr >= 0x3a00) - scsi->ext_ram[addr - 0x3a00] = val; + ncr_dev->ext_ram[addr - 0x3a00] = val; else switch (addr & 0x3f80) { case 0x3800: #if 0 ncr_log("Write intram %02x %02x\n", addr & 0x3f, val); #endif - scsi->int_ram[addr & 0x3f] = val; + ncr_dev->int_ram[addr & 0x3f] = val; break; case 0x3880: #if ENABLE_NCR5380_LOG ncr_log("Write 53c80 %04x %02x\n", addr, val); #endif - ncr_write(addr, val, scsi); + ncr_write(addr, val, ncr_dev); break; - + case 0x3900: - if (!(scsi->status_ctrl & CTRL_DATA_DIR) && scsi->buffer_host_pos < 128) { - scsi->buffer[scsi->buffer_host_pos++] = val; - if (scsi->buffer_host_pos == 128) { - scsi->status_ctrl |= STATUS_BUFFER_NOT_READY; - scsi->ncr_busy = 1; + if (!(ncr_dev->status_ctrl & CTRL_DATA_DIR) && ncr_dev->buffer_host_pos < 128) { + ncr_dev->buffer[ncr_dev->buffer_host_pos++] = val; + + if (ncr_dev->buffer_host_pos == 128) + { + ncr_dev->status_ctrl |= STATUS_BUFFER_NOT_READY; + ncr_dev->ncr_busy = 1; } } break; @@ -631,31 +670,45 @@ memio_write(uint32_t addr, uint8_t val, void *priv) case 0x3980: switch (addr) { case 0x3980: /* Control */ - if ((val & CTRL_DATA_DIR) && !(scsi->status_ctrl & CTRL_DATA_DIR)) { - scsi->buffer_host_pos = 128; - scsi->status_ctrl |= STATUS_BUFFER_NOT_READY; + ncr_log("Write 0x3980: val=%02x CS=%04x, pc=%04x\n", val, CS,cpu_state.pc); + if (val & 0x80) + { + ncr_log("Resetting the 53c400\n"); + picint(1 << ncr_dev->irq); } - else if (!(val & CTRL_DATA_DIR) && (scsi->status_ctrl & CTRL_DATA_DIR)) { - scsi->buffer_host_pos = 0; - scsi->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + + if ((val & CTRL_DATA_DIR) && !(ncr_dev->status_ctrl & CTRL_DATA_DIR)) { + ncr_log("Pos 128\n"); + ncr_dev->buffer_host_pos = 128; + ncr_dev->status_ctrl |= STATUS_BUFFER_NOT_READY; } - scsi->status_ctrl = (scsi->status_ctrl & 0x87) | (val & 0x78); + else if (!(val & CTRL_DATA_DIR) && (ncr_dev->status_ctrl & CTRL_DATA_DIR)) { + ncr_log("Pos 0\n"); + ncr_dev->buffer_host_pos = 0; + ncr_dev->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + } + ncr_dev->status_ctrl = (ncr_dev->status_ctrl & 0x87) | (val & 0x78); break; case 0x3981: /* block counter register */ - scsi->block_count = val; - scsi->block_count_loaded = 1; - scsi->dma_enabled = (scsi->ncr5380_dma_enabled && scsi->block_count_loaded); - if (scsi->status_ctrl & CTRL_DATA_DIR) { - scsi->buffer_host_pos = 128; - scsi->status_ctrl |= STATUS_BUFFER_NOT_READY; + ncr_log("Write 0x3981: val=%d\n", val); + ncr_dev->block_count = val; + ncr_dev->block_count_loaded = 1; + + ncr_log("Timer for transfers=%02x\n", ncr_dev->timer_enabled); + + if (ncr_dev->status_ctrl & CTRL_DATA_DIR) { + ncr_log("Data Read\n"); + ncr_dev->buffer_host_pos = 128; + ncr_dev->status_ctrl |= STATUS_BUFFER_NOT_READY; } else { - scsi->buffer_host_pos = 0; - scsi->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + ncr_log("Data Write\n"); + ncr_dev->buffer_host_pos = 0; + ncr_dev->status_ctrl &= ~STATUS_BUFFER_NOT_READY; } break; } - break; + break; } } @@ -664,18 +717,15 @@ memio_write(uint32_t addr, uint8_t val, void *priv) static uint8_t t130b_read(uint32_t addr, void *priv) { - ncr_t *scsi = (ncr_t *)priv; + ncr5380_t *ncr_dev = (ncr5380_t *)priv; uint8_t ret = 0xff; addr &= 0x3fff; - if ((addr < 0x1800) && scsi->rom_addr) - ret = scsi->bios_rom.rom[addr & 0x1fff]; - else - if ((addr < 0x1800) && !scsi->rom_addr) - ret = 0xff; + if (addr < 0x1800) + ret = ncr_dev->bios_rom.rom[addr & 0x1fff]; else if (addr < 0x1880) - ret = scsi->ext_ram[addr & 0x7f]; + ret = ncr_dev->ext_ram[addr & 0x7f]; return(ret); } @@ -685,18 +735,18 @@ t130b_read(uint32_t addr, void *priv) static void t130b_write(uint32_t addr, uint8_t val, void *priv) { - ncr_t *scsi = (ncr_t *)priv; + ncr5380_t *ncr_dev = (ncr5380_t *)priv; addr &= 0x3fff; if (addr >= 0x1800 && addr < 0x1880) - scsi->ext_ram[addr & 0x7f] = val; + ncr_dev->ext_ram[addr & 0x7f] = val; } static uint8_t t130b_in(uint16_t port, void *priv) { - ncr_t *scsi = (ncr_t *)priv; + ncr5380_t *ncr_dev = (ncr5380_t *)priv; uint8_t ret = 0xff; switch (port & 0x0f) { @@ -704,14 +754,14 @@ t130b_in(uint16_t port, void *priv) case 0x01: case 0x02: case 0x03: - ret = memio_read((port & 7) | 0x3980, scsi); + ret = memio_read((port & 7) | 0x3980, ncr_dev); break; case 0x04: case 0x05: - ret = memio_read(0x3900, scsi); - break; - + ret = memio_read(0x3900, ncr_dev); + break; + case 0x08: case 0x09: case 0x0a: @@ -720,7 +770,7 @@ t130b_in(uint16_t port, void *priv) case 0x0d: case 0x0e: case 0x0f: - ret = ncr_read(port, scsi); + ret = ncr_read(port, ncr_dev); break; } @@ -731,21 +781,21 @@ t130b_in(uint16_t port, void *priv) static void t130b_out(uint16_t port, uint8_t val, void *priv) { - ncr_t *scsi = (ncr_t *)priv; + ncr5380_t *ncr_dev = (ncr5380_t *)priv; switch (port & 0x0f) { case 0x00: case 0x01: case 0x02: case 0x03: - memio_write((port & 7) | 0x3980, val, scsi); + memio_write((port & 7) | 0x3980, val, ncr_dev); break; case 0x04: case 0x05: - memio_write(0x3900, val, scsi); - break; - + memio_write(0x3900, val, ncr_dev); + break; + case 0x08: case 0x09: case 0x0a: @@ -754,16 +804,15 @@ t130b_out(uint16_t port, uint8_t val, void *priv) case 0x0d: case 0x0e: case 0x0f: - ncr_write(port, val, scsi); + ncr_write(port, val, ncr_dev); break; } } - static uint8_t scsiat_in(uint16_t port, void *priv) { - ncr_t *scsi = (ncr_t *)priv; + ncr5380_t *ncr_dev = (ncr5380_t *)priv; uint8_t ret = 0xff; switch (port & 0x0f) { @@ -771,26 +820,16 @@ scsiat_in(uint16_t port, void *priv) case 0x01: case 0x02: case 0x03: - ret = memio_read((port & 7) | 0x3980, scsi); - break; - case 0x04: case 0x05: - ret = memio_read(0x3900, scsi); - break; - - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - ret = ncr_read(port, scsi); + case 0x06: + case 0x07: + ret = ncr_read(port, ncr_dev); break; } + pclog("SCSI AT read=0x%03x, ret=%02x, CS:%08x, PC:%08x\n", port, ret, CS,cpu_state.pc); + return(ret); } @@ -798,31 +837,601 @@ scsiat_in(uint16_t port, void *priv) static void scsiat_out(uint16_t port, uint8_t val, void *priv) { - ncr_t *scsi = (ncr_t *)priv; + ncr5380_t *ncr_dev = (ncr5380_t *)priv; + ncr_t *ncr = &ncr_dev->ncr; + scsi_device_t *dev = &SCSIDevices[ncr->target_id]; + pclog("SCSI AT write=0x%03x, val=%02x, CS:%08x, PC:%08x\n", port, val, CS,cpu_state.pc); switch (port & 0x0f) { + case 0x08: + ncr->unk_08 = val; + + if (ncr->unk_08 & 0x08) + { + if (ncr->dma_mode == DMA_INITIATOR_RECEIVE) + { + while (ncr_dev->buffer_host_pos < 128) + { + uint8_t temp; + + temp = ncr_dev->buffer[ncr_dev->buffer_host_pos++]; + + pclog("Read Buffer host=%d\n", ncr_dev->buffer_host_pos); + + ncr->bus_host = get_bus_host(ncr) & ~BUS_DATAMASK; + ncr->bus_host |= BUS_SETDATA(temp); + + if (ncr_dev->buffer_host_pos == 128) + break; + } + } + else if (ncr->dma_mode == DMA_SEND) + { + while (ncr_dev->buffer_host_pos < 128) + { + /* Data ready. */ + uint8_t temp; + + ncr_wait_process(ncr_dev); + temp = BUS_GETDATA(ncr->bus_host); + ncr->bus_host = get_bus_host(ncr); + + ncr_dev->buffer[ncr_dev->buffer_host_pos++] = temp; + + pclog("Write Buffer host=%d\n", ncr_dev->buffer_host_pos); + + if (ncr_dev->buffer_host_pos == 128) + { + + break; + } + } + } + } + + if (ncr->unk_08 & 0x01) + { + ncr_dev->block_count_loaded = 1; + ncr_dev->block_count = dev->BufferLength / 128; + } + break; + case 0x00: case 0x01: case 0x02: case 0x03: - memio_write((port & 7) | 0x3980, val, scsi); - break; - case 0x04: case 0x05: - memio_write(0x3900, val, scsi); + case 0x06: + case 0x07: + ncr_write(port, val, ncr_dev); break; + } +} - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - ncr_write(port, val, scsi); - break; +static void +ncr_callback(void *priv) +{ + ncr5380_t *ncr_dev = (ncr5380_t *)priv; + ncr_t *ncr = &ncr_dev->ncr; + scsi_device_t *dev = &SCSIDevices[ncr->target_id]; + int c = 0; + + ncr_log("DMA mode=%d\n", ncr->dma_mode); + + if (!ncr_dev->timer_enabled) + { + if (ncr->dma_mode == DMA_IDLE) + { + ncr_dev->timer_period = 10LL * TIMER_USEC; + return; + } + else + { + ncr_dev->timer_period += 10LL * TIMER_USEC; + } + } + else + { + ncr_dev->timer_enabled = 0; + } + + if (ncr->dma_mode == DMA_IDLE) + { + ncr->bus_host = get_bus_host(ncr); + + /*Start the SCSI command layer, which will also make the timings*/ + if (ncr->bus_host & BUS_ARB) + { + ncr_log("Arbitration\n"); + ncr->state = STATE_IDLE; + } + + if (ncr->state == STATE_IDLE) + { + ncr->clear_req = ncr->wait_data = ncr->wait_complete = 0; + if ((ncr->bus_host & BUS_SEL) && !(ncr->bus_host & BUS_BSY)) + { + ncr_log("Selection phase\n"); + uint8_t sel_data = BUS_GETDATA(ncr->bus_host); + + ncr->target_id = get_dev_id(sel_data); + + ncr_log("Select - target ID = %i\n", ncr->target_id); + + /*Once the device has been found and selected, mark it as busy*/ + if ((ncr->target_id != -1) && scsi_device_present(ncr->target_id)) { + ncr->cur_bus |= BUS_BSY; + ncr_log("Device found at ID %i\n", ncr->target_id); + ncr_log("Current Bus BSY=%02x\n", ncr->cur_bus); + ncr->state = STATE_COMMAND; + ncr->cur_bus = BUS_BSY | BUS_REQ; + ncr_log("CurBus BSY|REQ=%02x\n", ncr->cur_bus); + ncr->command_pos = 0; + SET_BUS_STATE(ncr, SCSI_PHASE_COMMAND); + picint(1 << ncr_dev->irq); + } + else + { + ncr->state = STATE_IDLE; + ncr->cur_bus = 0; + } + } + } + else if (ncr->state == STATE_COMMAND) + { + int64_t p; + + /*Command phase, make sure the ICR ACK bit is set to keep on, + because the device must be acknowledged by ICR*/ + ncr_log("NCR ICR for Command=%02x\n", ncr->bus_host & BUS_ACK); + if (ncr->bus_host & BUS_ACK) + { + /*Write command byte to the output data register*/ + ncr->command[ncr->command_pos++] = BUS_GETDATA(ncr->bus_host); + + ncr->new_phase = ncr->cur_bus & SCSI_PHASE_MESSAGE_IN; + ncr->clear_req = 3; + ncr_log("Current bus for command request=%02x\n", ncr->cur_bus & BUS_REQ); + ncr->cur_bus &= ~BUS_REQ; + + ncr_log("Command pos=%i, output data=%02x\n", ncr->command_pos, BUS_GETDATA(ncr->bus_host)); + if (get_cmd_len(ncr->command[0]) == ncr->command_pos) + { + /*Reset data position to default*/ + ncr->data_pos = 0; + + dev = &SCSIDevices[ncr->target_id]; + + ncr_log("SCSI Command 0x%02X for ID %d, status code=%02x\n", ncr->command[0], ncr->target_id, dev->Status); + + dev->BufferLength = -1; + + /*Now, execute the given SCSI command*/ + scsi_device_command_phase0(ncr->target_id, ncr->command); + + ncr_log("SCSI ID %i: Command %02X: Buffer Length %i, SCSI Phase %02X\n", ncr->target_id, ncr->command[0], dev->BufferLength, dev->Phase); + + if (dev->Status != SCSI_STATUS_OK) + ncr_dev->is_non_data_mode = 1; + + if (ncr_dev->is_non_data_mode) + { + ncr_dev->is_non_data_mode = 0; + ncr->new_phase = SCSI_PHASE_STATUS; + ncr->wait_data = 4; + return; + } + + /*If the SCSI phase is Data In or Data Out, allocate the SCSI buffer based on the transfer length of the command*/ + if (dev->BufferLength && (dev->Phase == SCSI_PHASE_DATA_IN || dev->Phase == SCSI_PHASE_DATA_OUT)) { + dev->CmdBuffer = (uint8_t *) malloc(dev->BufferLength); + + p = scsi_device_get_callback(ncr->target_id); + if (p <= 0LL) { + ncr_dev->temp_period += (int64_t)(dev->BufferLength); + } else { + ncr_dev->media_period += p; + } + } + + if (dev->Phase == SCSI_PHASE_DATA_OUT) { + /* Write direction commands have delayed execution - only execute them after the bus has gotten all the data from the host. */ + ncr_log("Next state is data out\n"); + ncr->new_phase = SCSI_PHASE_DATA_OUT; + ncr->wait_data = 4; + ncr->clear_req = 4; + } else { + /* Other command - execute immediately. */ + ncr->new_phase = dev->Phase; + + if (ncr->new_phase == SCSI_PHASE_DATA_IN) + { + scsi_device_command_phase1(ncr->target_id); + } + + ncr->wait_data = 4; + } + } + } + } + else if (ncr->state == STATE_DATAIN) + { + dev = &SCSIDevices[ncr->target_id]; + ncr_log("Data In ACK=%02x\n", ncr->bus_host & BUS_ACK); + if (ncr->bus_host & BUS_ACK) + { + if (ncr->data_pos >= dev->BufferLength) { + + if (dev->CmdBuffer != NULL) + { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + ncr->cur_bus &= ~BUS_REQ; + ncr->new_phase = SCSI_PHASE_STATUS; + ncr->wait_data = 4; + ncr->wait_complete = 8; + } else { + ncr->tx_data = dev->CmdBuffer[ncr->data_pos++]; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ; + ncr->clear_req = 3; + ncr->cur_bus &= ~BUS_REQ; + ncr->new_phase = SCSI_PHASE_DATA_IN; + } + } + } + else if (ncr->state == STATE_DATAOUT) + { + dev = &SCSIDevices[ncr->target_id]; + + ncr_log("Data Out ACK=%02x\n", ncr->bus_host & BUS_ACK); + if (ncr->bus_host & BUS_ACK) + { + dev->CmdBuffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host); + + if (ncr->data_pos >= dev->BufferLength) { + scsi_device_command_phase1(ncr->target_id); + + if (dev->CmdBuffer != NULL) + { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + ncr->cur_bus &= ~BUS_REQ; + ncr_log("CurBus ~REQ_DataOutDone=%02x\n", ncr->cur_bus); + ncr->new_phase = SCSI_PHASE_STATUS; + ncr->wait_data = 4; + ncr->wait_complete = 8; + } + else + { + /*More data is to be transferred, place a request*/ + ncr->cur_bus |= BUS_REQ; + ncr_log("CurBus ~REQ_DataOut=%02x\n", ncr->cur_bus); + } + } + } + else if (ncr->state == STATE_STATUS) + { + if (ncr->bus_host & BUS_ACK) + { + /*All transfers done, wait until next transfer*/ + ncr->cur_bus &= ~BUS_REQ; + ncr->new_phase = SCSI_PHASE_MESSAGE_IN; + ncr->wait_data = 4; + ncr->wait_complete = 8; + } + } + else if (ncr->state == STATE_MESSAGEIN) + { + if (ncr->bus_host & BUS_ACK) + { + ncr->cur_bus &= ~BUS_REQ; + ncr->new_phase = BUS_IDLE; + ncr->wait_data = 4; + } + } + } + + if (ncr_dev->type < 3) + { + if (((ncr_dev->status_ctrl & STATUS_BUFFER_NOT_READY) && + (ncr->dma_mode == DMA_SEND || ncr->dma_mode == DMA_INITIATOR_RECEIVE))) + { + ncr_dev->period = 0.2 * ((double) TIMER_USEC) * ((double) ncr_dev->temp_period); + ncr_dev->timer_period = (ncr_dev->media_period + ((int64_t) ncr_dev->period) + (40LL * TIMER_USEC)) / 450; + ncr_log("Temporary period: %" PRId64 " us (%" PRIi64 " periods), media periods = %" PRId64 " \n", ncr_dev->timer_period, ncr_dev->temp_period, ncr_dev->media_period); + } + + if (ncr->dma_mode == DMA_INITIATOR_RECEIVE) + { + if (!(ncr_dev->status_ctrl & CTRL_DATA_DIR)) { + ncr_log("DMA_INITIATOR_RECEIVE with DMA direction set wrong\n"); + return; + } + + ncr_log("Status for reading=%02x\n", ncr_dev->status_ctrl); + + if (!(ncr_dev->status_ctrl & STATUS_BUFFER_NOT_READY)) return; + + if (!ncr_dev->block_count_loaded) return; + + while (c < 64) + { + /* Data ready. */ + uint8_t temp; + + ncr_wait_process(ncr_dev); + temp = BUS_GETDATA(ncr->bus_host); + ncr->bus_host = get_bus_host(ncr); + + if (ncr->data_pos >= dev->BufferLength) { + + if (dev->CmdBuffer != NULL) + { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + ncr->cur_bus &= ~BUS_REQ; + ncr->new_phase = SCSI_PHASE_STATUS; + ncr->wait_data = 4; + ncr->wait_complete = 8; + } else { + ncr->tx_data = dev->CmdBuffer[ncr->data_pos++]; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ; + ncr->clear_req = 3; + ncr->cur_bus &= ~BUS_REQ; + ncr->new_phase = SCSI_PHASE_DATA_IN; + } + + ncr_dev->buffer[ncr_dev->buffer_pos++] = temp; + ncr_log("Buffer pos for reading=%d\n", ncr_dev->buffer_pos); + + c++; + + if (ncr_dev->buffer_pos == 128) + { + ncr_dev->buffer_pos = 0; + ncr_dev->buffer_host_pos = 0; + ncr_dev->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + ncr_dev->block_count = (ncr_dev->block_count - 1) & 255; + ncr_log("Remaining blocks to be read=%d\n", ncr_dev->block_count); + if (!ncr_dev->block_count) { + ncr_dev->block_count_loaded = 0; + ncr_log("IO End of read transfer\n"); + + ncr->isr |= STATUS_END_OF_DMA; + if (ncr->mode & MODE_ENA_EOP_INT) + { + ncr_log("NCR read irq\n"); + ncr->isr |= STATUS_INT; + picint(1 << ncr_dev->irq); + } + } + break; + } + } + } + else if (ncr->dma_mode == DMA_SEND) + { + if (ncr_dev->status_ctrl & CTRL_DATA_DIR) { + ncr_log("DMA_SEND with DMA direction set wrong\n"); + return; + } + + ncr_log("Status for writing=%02x\n", ncr_dev->status_ctrl); + + if (!(ncr_dev->status_ctrl & STATUS_BUFFER_NOT_READY)) + { + ncr_log("Buffer ready\n"); + return; + } + + if (!ncr_dev->block_count_loaded) return; + + while (c < 64) + { + /* Data ready. */ + uint8_t data; + + data = ncr_dev->buffer[ncr_dev->buffer_pos]; + ncr->bus_host = get_bus_host(ncr) & ~BUS_DATAMASK; + ncr->bus_host |= BUS_SETDATA(data); + + dev->CmdBuffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host); + + if (ncr->data_pos >= dev->BufferLength) { + scsi_device_command_phase1(ncr->target_id); + + if (dev->CmdBuffer != NULL) + { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + ncr->cur_bus &= ~BUS_REQ; + ncr_log("CurBus ~REQ_DataOutDone=%02x\n", ncr->cur_bus); + ncr->new_phase = SCSI_PHASE_STATUS; + ncr->wait_data = 4; + ncr->wait_complete = 8; + } + else + { + /*More data is to be transferred, place a request*/ + ncr->cur_bus |= BUS_REQ; + ncr_log("CurBus ~REQ_DataOut=%02x\n", ncr->cur_bus); + } + + c++; + + if (++ncr_dev->buffer_pos == 128) { + ncr_dev->buffer_pos = 0; + ncr_dev->buffer_host_pos = 0; + ncr_dev->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + ncr_dev->ncr_busy = 0; + ncr_dev->block_count = (ncr_dev->block_count - 1) & 255; + ncr_log("Remaining blocks to be written=%d\n", ncr_dev->block_count); + if (!ncr_dev->block_count) { + ncr_dev->block_count_loaded = 0; + ncr_log("IO End of write transfer\n"); + + ncr->tcr |= TCR_LAST_BYTE_SENT; + ncr->isr |= STATUS_END_OF_DMA; + if (ncr->mode & MODE_ENA_EOP_INT) + { + ncr_log("NCR write irq\n"); + ncr->isr |= STATUS_INT; + picint(1 << ncr_dev->irq); + } + } + break; + } + } + } + } + else + { + if (((ncr->unk_08 & 0x01) && + (ncr->dma_mode == DMA_SEND || ncr->dma_mode == DMA_INITIATOR_RECEIVE))) + { + ncr_dev->period = 0.2 * ((double) TIMER_USEC) * ((double) ncr_dev->temp_period); + ncr_dev->timer_period = (ncr_dev->media_period + ((int64_t) ncr_dev->period) + (40LL * TIMER_USEC)) / 450; + ncr_log("Temporary period: %" PRId64 " us (%" PRIi64 " periods), media periods = %" PRId64 " \n", ncr_dev->timer_period, ncr_dev->temp_period, ncr_dev->media_period); + } + + if (ncr->dma_mode == DMA_INITIATOR_RECEIVE) + { + if (!(ncr_dev->block_count_loaded)) + return; + + while (c < 64) + { + /* Data ready. */ + uint8_t temp; + + ncr_wait_process(ncr_dev); + temp = BUS_GETDATA(ncr->bus_host); + ncr->bus_host = get_bus_host(ncr); + + if (ncr->data_pos >= dev->BufferLength) { + + if (dev->CmdBuffer != NULL) + { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + ncr->cur_bus &= ~BUS_REQ; + ncr->new_phase = SCSI_PHASE_STATUS; + ncr->wait_data = 4; + ncr->wait_complete = 8; + } else { + ncr->tx_data = dev->CmdBuffer[ncr->data_pos++]; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ; + ncr->clear_req = 3; + ncr->cur_bus &= ~BUS_REQ; + ncr->new_phase = SCSI_PHASE_DATA_IN; + } + + ncr_dev->buffer[ncr_dev->buffer_pos++] = temp; + pclog("Buffer pos for reading=%d\n", ncr_dev->buffer_pos); + + c++; + + if (ncr_dev->buffer_pos == 128) + { + ncr_dev->buffer_pos = 0; + ncr_dev->buffer_host_pos = 0; + ncr_dev->block_count = (ncr_dev->block_count - 1) & 255; + pclog("Remaining blocks to be read=%d\n", ncr_dev->block_count); + if (!ncr_dev->block_count) { + ncr_dev->block_count_loaded = 0; + ncr_log("IO End of read transfer\n"); + + ncr->isr |= STATUS_END_OF_DMA; + if (ncr->mode & MODE_ENA_EOP_INT) + { + ncr_log("NCR read irq\n"); + ncr->isr |= STATUS_INT; + picint(1 << ncr_dev->irq); + } + } + break; + } + } + } + else if (ncr->dma_mode == DMA_SEND) + { + if (!ncr_dev->block_count_loaded) return; + + while (c < 64) + { + /* Data ready. */ + uint8_t data; + + data = ncr_dev->buffer[ncr_dev->buffer_pos]; + ncr->bus_host = get_bus_host(ncr) & ~BUS_DATAMASK; + ncr->bus_host |= BUS_SETDATA(data); + + dev->CmdBuffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host); + + if (ncr->data_pos >= dev->BufferLength) { + scsi_device_command_phase1(ncr->target_id); + + if (dev->CmdBuffer != NULL) + { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + ncr->cur_bus &= ~BUS_REQ; + ncr_log("CurBus ~REQ_DataOutDone=%02x\n", ncr->cur_bus); + ncr->new_phase = SCSI_PHASE_STATUS; + ncr->wait_data = 4; + ncr->wait_complete = 8; + } + else + { + /*More data is to be transferred, place a request*/ + ncr->cur_bus |= BUS_REQ; + ncr_log("CurBus ~REQ_DataOut=%02x\n", ncr->cur_bus); + } + + c++; + + if (++ncr_dev->buffer_pos == 128) { + ncr_dev->buffer_pos = 0; + ncr_dev->buffer_host_pos = 0; + ncr_dev->block_count = (ncr_dev->block_count - 1) & 255; + pclog("Remaining blocks to be written=%d\n", ncr_dev->block_count); + if (!ncr_dev->block_count) { + ncr_dev->block_count_loaded = 0; + ncr_log("IO End of write transfer\n"); + + ncr->tcr |= TCR_LAST_BYTE_SENT; + ncr->isr |= STATUS_END_OF_DMA; + if (ncr->mode & MODE_ENA_EOP_INT) + { + ncr_log("NCR write irq\n"); + ncr->isr |= STATUS_INT; + picint(1 << ncr_dev->irq); + } + } + break; + } + } + } + } + + ncr_wait_process(ncr_dev); + if (!(ncr->bus_host & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) { + pclog("Updating DMA\n"); + ncr->mode &= ~MODE_DMA; + ncr->dma_mode = DMA_IDLE; } } @@ -831,127 +1440,107 @@ static void * ncr_init(const device_t *info) { char temp[128]; - ncr_t *scsi; + ncr5380_t *ncr_dev; - scsi = malloc(sizeof(ncr_t)); - memset(scsi, 0x00, sizeof(ncr_t)); - scsi->name = info->name; - scsi->type = info->local; + ncr_dev = malloc(sizeof(ncr5380_t)); + memset(ncr_dev, 0x00, sizeof(ncr5380_t)); + ncr_dev->name = info->name; + ncr_dev->type = info->local; - switch(scsi->type) { + switch(ncr_dev->type) { case 0: /* Longshine LCS6821N */ - scsi->rom_addr = 0xDC000; - rom_init(&scsi->bios_rom, LCS6821N_ROM, - scsi->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - mem_mapping_disable(&scsi->bios_rom.mapping); + ncr_dev->rom_addr = 0xDC000; + rom_init(&ncr_dev->bios_rom, LCS6821N_ROM, + ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + mem_mapping_disable(&ncr_dev->bios_rom.mapping); - mem_mapping_add(&scsi->mapping, scsi->rom_addr, 0x4000, + mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, memio_read, NULL, NULL, memio_write, NULL, NULL, - scsi->bios_rom.rom, 0, scsi); + ncr_dev->bios_rom.rom, 0, ncr_dev); break; - case 1: /* Ranco RT1000B */ - scsi->base = device_get_config_hex16("base"); - scsi->rom_addr = device_get_config_hex20("bios_addr"); + case 1: /* Rancho RT1000B */ + ncr_dev->rom_addr = 0xDC000; + rom_init(&ncr_dev->bios_rom, RT1000B_ROM, + ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - if (scsi->rom_addr) { - rom_init(&scsi->bios_rom, RT1000B_ROM, - scsi->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + mem_mapping_disable(&ncr_dev->bios_rom.mapping); - mem_mapping_disable(&scsi->bios_rom.mapping); - } else { - scsi->bios_rom.rom = (uint8_t *) malloc(0x4000); - memset(scsi->bios_rom.rom, 0xff, 0x4000); - } - - mem_mapping_add(&scsi->mapping, scsi->rom_addr, 0x4000, + mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, memio_read, NULL, NULL, memio_write, NULL, NULL, - scsi->bios_rom.rom, 0, scsi); - - if (scsi->base) { - io_sethandler(scsi->base, 16, - t130b_in,NULL,NULL, t130b_out,NULL,NULL, scsi); - } + ncr_dev->bios_rom.rom, 0, ncr_dev); break; case 2: /* Trantor T130B */ - scsi->base = device_get_config_hex16("base"); - scsi->rom_addr = device_get_config_hex20("bios_addr"); + ncr_dev->rom_addr = 0xDC000; + ncr_dev->base = device_get_config_hex16("base"); + ncr_dev->irq = device_get_config_int("irq"); + rom_init(&ncr_dev->bios_rom, T130B_ROM, + ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - if (scsi->rom_addr) { - rom_init(&scsi->bios_rom, T130B_ROM, - scsi->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - - mem_mapping_disable(&scsi->bios_rom.mapping); - } else { - scsi->bios_rom.rom = (uint8_t *) malloc(0x4000); - memset(scsi->bios_rom.rom, 0xff, 0x4000); - } - - mem_mapping_add(&scsi->mapping, scsi->rom_addr, 0x4000, + mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, t130b_read, NULL, NULL, t130b_write, NULL, NULL, - scsi->bios_rom.rom, 0, scsi); + ncr_dev->bios_rom.rom, 0, ncr_dev); - if (scsi->base) { - io_sethandler(scsi->base, 16, - t130b_in,NULL,NULL, t130b_out,NULL,NULL, scsi); - } + io_sethandler(ncr_dev->base, 16, + t130b_in,NULL,NULL, t130b_out,NULL,NULL, ncr_dev); break; case 3: /* Sumo SCSI-AT */ - scsi->base = device_get_config_hex16("base"); - scsi->irq = device_get_config_int("irq"); - scsi->rom_addr = device_get_config_hex20("bios_addr"); + ncr_dev->base = device_get_config_hex16("base"); + ncr_dev->irq = device_get_config_int("irq"); + ncr_dev->rom_addr = device_get_config_hex20("bios_addr"); + rom_init(&ncr_dev->bios_rom, SCSIAT_ROM, + ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - if (scsi->rom_addr) { - rom_init(&scsi->bios_rom, SCSIAT_ROM, - scsi->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - - mem_mapping_disable(&scsi->bios_rom.mapping); - } else { - scsi->bios_rom.rom = (uint8_t *) malloc(0x4000); - memset(scsi->bios_rom.rom, 0xff, 0x4000); - } - - mem_mapping_add(&scsi->mapping, scsi->rom_addr, 0x4000, + mem_mapping_disable(&ncr_dev->bios_rom.mapping); + + mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, t130b_read, NULL, NULL, t130b_write, NULL, NULL, - scsi->bios_rom.rom, 0, scsi); + ncr_dev->bios_rom.rom, 0, ncr_dev); - if (scsi->base) { - io_sethandler(scsi->base, 16, - scsiat_in,NULL,NULL, scsiat_out,NULL,NULL, scsi); - } + io_sethandler(ncr_dev->base, 16, + scsiat_in,NULL,NULL, scsiat_out,NULL,NULL, ncr_dev); break; } - sprintf(temp, "%s: BIOS=%05X", scsi->name, scsi->rom_addr); - if (scsi->base != 0) - sprintf(&temp[strlen(temp)], " I/O=%04x", scsi->base); - if (scsi->irq != 0) - sprintf(&temp[strlen(temp)], " IRQ=%d", scsi->irq); + sprintf(temp, "%s: BIOS=%05X", ncr_dev->name, ncr_dev->rom_addr); + if (ncr_dev->base != 0) + sprintf(&temp[strlen(temp)], " I/O=%04x", ncr_dev->base); + if (ncr_dev->irq != 0) + sprintf(&temp[strlen(temp)], " IRQ=%d", ncr_dev->irq); ncr_log("%s\n", temp); - ncr5380_reset(&scsi->ncr); - - scsi->status_ctrl = STATUS_BUFFER_NOT_READY; - scsi->buffer_host_pos = 128; - - timer_add(dma_callback, &scsi->dma_timer, &scsi->dma_enabled, scsi); - - return(scsi); + ncr_reset(&ncr_dev->ncr); + ncr_dev->status_ctrl = STATUS_BUFFER_NOT_READY; + ncr_dev->buffer_host_pos = 128; + + ncr_dev->timer_period = 10LL * TIMER_USEC; + timer_add(ncr_callback, &ncr_dev->timer_period, TIMER_ALWAYS_ENABLED, ncr_dev); + + return(ncr_dev); } static void ncr_close(void *priv) { - ncr_t *scsi = (ncr_t *)priv; + ncr5380_t *ncr_dev = (ncr5380_t *)priv; - free(scsi); + if (ncr_dev) + { + /* Tell the timer to terminate. */ + ncr_dev->timer_period = 0LL; + ncr_dev->timer_enabled = 0LL; + + free(ncr_dev); + ncr_dev = NULL; + } } @@ -982,14 +1571,10 @@ scsiat_available(void) return(rom_present(SCSIAT_ROM)); } - -static const device_config_t ncr5380_config[] = { +static const device_config_t t130b_config[] = { { "base", "Address", CONFIG_HEX16, "", 0x0350, { - { - "None", 0 - }, { "240H", 0x0240 }, @@ -1008,22 +1593,16 @@ static const device_config_t ncr5380_config[] = { }, }, { - "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0xDC000, + "irq", "IRQ", CONFIG_SELECTION, "", 5, { { - "Disabled", 0 + "IRQ 3", 3 }, { - "C800H", 0xc8000 + "IRQ 5", 5 }, { - "CC00H", 0xcc000 - }, - { - "D800H", 0xd8000 - }, - { - "DC00H", 0xdc000 + "IRQ 7", 7 }, { "" @@ -1035,7 +1614,6 @@ static const device_config_t ncr5380_config[] = { } }; - static const device_config_t scsiat_config[] = { { "base", "Address", CONFIG_HEX16, "", 0x0310, @@ -1146,13 +1724,13 @@ const device_t scsi_lcs6821n_device = const device_t scsi_rt1000b_device = { - "Ranco RT1000B", + "Rancho RT1000B", DEVICE_ISA, 1, ncr_init, ncr_close, NULL, rt1000b_available, NULL, NULL, - ncr5380_config + NULL }; const device_t scsi_t130b_device = @@ -1163,7 +1741,7 @@ const device_t scsi_t130b_device = ncr_init, ncr_close, NULL, t130b_available, NULL, NULL, - ncr5380_config + t130b_config }; const device_t scsi_scsiat_device = diff --git a/src/video/vid_et4000.c b/src/video/vid_et4000.c index 5db6c55d9..6f2cb5cd3 100644 --- a/src/video/vid_et4000.c +++ b/src/video/vid_et4000.c @@ -23,6 +23,7 @@ #include #include "../86box.h" #include "../io.h" +#include "../mca.h" #include "../mem.h" #include "../rom.h" #include "../device.h" @@ -43,6 +44,10 @@ typedef struct et4000_t rom_t bios_rom; uint8_t banking; + + uint8_t pos_regs[8]; + + int is_mca; } et4000_t; static uint8_t crtc_mask[0x40] = @@ -112,6 +117,16 @@ uint8_t et4000_in(uint16_t addr, void *p) switch (addr) { + case 0x3c2: + if (et4000->is_mca) + { + if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x4e) + return 0; + else + return 0x10; + } + break; + case 0x3C5: if ((svga->seqaddr & 0xf) == 7) return svga->seqregs[svga->seqaddr & 0xf] | 4; break; @@ -160,11 +175,13 @@ void et4000_recalctimings(svga_t *svga) } } -void *et4000_init(const device_t *info) +void *et4000_isa_init(const device_t *info) { et4000_t *et4000 = malloc(sizeof(et4000_t)); memset(et4000, 0, sizeof(et4000_t)); + et4000->is_mca = 0; + rom_init(&et4000->bios_rom, BIOS_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); io_sethandler(0x03c0, 0x0020, et4000_in, NULL, NULL, et4000_out, NULL, NULL, et4000); @@ -178,6 +195,51 @@ void *et4000_init(const device_t *info) return et4000; } +static uint8_t +et4000_mca_read(int port, void *priv) +{ + et4000_t *et4000 = (et4000_t *)priv; + + return(et4000->pos_regs[port & 7]); +} + +static void +et4000_mca_write(int port, uint8_t val, void *priv) +{ + et4000_t *et4000 = (et4000_t *)priv; + + /* MCA does not write registers below 0x0100. */ + if (port < 0x0102) return; + + /* Save the MCA register value. */ + et4000->pos_regs[port & 7] = val; +} + +void *et4000_mca_init(const device_t *info) +{ + et4000_t *et4000 = malloc(sizeof(et4000_t)); + memset(et4000, 0, sizeof(et4000_t)); + + et4000->is_mca = 1; + + /* Enable MCA. */ + et4000->pos_regs[0] = 0xF2; /* ET4000 MCA board ID */ + et4000->pos_regs[1] = 0x80; + mca_add(et4000_mca_read, et4000_mca_write, et4000); + + rom_init(&et4000->bios_rom, BIOS_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga_init(&et4000->svga, et4000, 1 << 20, /*1mb*/ + et4000_recalctimings, + et4000_in, et4000_out, + NULL, + NULL); + + io_sethandler(0x03c0, 0x0020, et4000_in, NULL, NULL, et4000_out, NULL, NULL, et4000); + + return et4000; +} + static int et4000_available(void) { return rom_present(BIOS_ROM_PATH); @@ -206,13 +268,25 @@ void et4000_force_redraw(void *p) et4000->svga.fullchange = changeframecount; } -const device_t et4000_device = +const device_t et4000_isa_device = { - "Tseng Labs ET4000AX", + "Tseng Labs ET4000AX (ISA)", DEVICE_ISA, 0, - et4000_init, et4000_close, NULL, + et4000_isa_init, et4000_close, NULL, et4000_available, et4000_speed_changed, et4000_force_redraw, NULL }; + +const device_t et4000_mca_device = +{ + "Tseng Labs ET4000AX (MCA)", + DEVICE_MCA, 0, + et4000_mca_init, et4000_close, NULL, + et4000_available, + et4000_speed_changed, + et4000_force_redraw, + NULL +}; + diff --git a/src/video/vid_et4000.h b/src/video/vid_et4000.h index 803f84729..d542efce6 100644 --- a/src/video/vid_et4000.h +++ b/src/video/vid_et4000.h @@ -1,4 +1,5 @@ /* Copyright holders: Sarah Walker see COPYING for more details */ -extern const device_t et4000_device; +extern const device_t et4000_isa_device; +extern const device_t et4000_mca_device; diff --git a/src/video/vid_table.c b/src/video/vid_table.c index a6d153367..46b87c8b8 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -126,10 +126,11 @@ video_cards[] = { { "[ISA] TI CF62011 SVGA", "ti_cf62011", &ti_cf62011_device, GFX_TICF62011, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, #endif {"[ISA] Trident TVGA8900D", "tvga8900d", &tvga8900d_device, GFX_TVGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}}, - {"[ISA] Tseng ET4000AX", "et4000ax", &et4000_device, GFX_ET4000, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, + {"[ISA] Tseng ET4000AX", "et4000ax", &et4000_isa_device, GFX_ET4000_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, {"[ISA] VGA", "vga", &vga_device, GFX_VGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, {"[ISA] Wyse 700", "wy700", &wy700_device, GFX_WY700, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - {"[PCI] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_pci", &mach64gx_pci_device, GFX_MACH64GX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}}, + {"[MCA] Tseng ET4000AX", "et4000mca", &et4000_mca_device, GFX_ET4000_MCA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 3, 6, 5, 5, 10}}, + {"[PCI] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_pci", &mach64gx_pci_device, GFX_MACH64GX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}}, {"[PCI] ATI Video Xpression (Mach64 VT2)", "mach64vt2", &mach64vt2_device, GFX_MACH64VT2, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}}, {"[PCI] Cardex Tseng ET4000/w32p", "et4000w32p_pci", &et4000w32p_cardex_pci_device, GFX_ET4000W32_CARDEX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 4, 10, 10, 10}}, {"[PCI] Cirrus Logic CL-GD 5430", "cl_gd5430_pci", &gd5430_pci_device, GFX_CL_GD5430_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, diff --git a/src/video/video.h b/src/video/video.h index fec490fb3..1144cbb48 100644 --- a/src/video/video.h +++ b/src/video/video.h @@ -44,7 +44,8 @@ enum { GFX_SUPER_EGA, /* Using Chips & Technologies SuperEGA BIOS */ GFX_VGA, /* IBM VGA */ GFX_TVGA, /* Using Trident TVGA8900D BIOS */ - GFX_ET4000, /* Tseng ET4000 */ + GFX_ET4000_ISA, /* Tseng ET4000 */ + GFX_ET4000_MCA, /* Tseng ET4000 */ GFX_ET4000W32_CARDEX_VLB, /* Tseng ET4000/W32p (Cardex) VLB */ GFX_ET4000W32_CARDEX_PCI, /* Tseng ET4000/W32p (Cardex) PCI */ #if defined(DEV_BRANCH) && defined(USE_STEALTH32) diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index b1e3dc761..405349dc5 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -490,7 +490,8 @@ NETOBJ := network.o \ ip_input.o queue.o tcp_input.o debug.o ip_output.o \ sbuf.o tcp_output.o udp.o if.o mbuf.o slirp.o tcp_subr.o \ net_dp8390.o \ - net_3c503.o net_ne2000.o + net_3c503.o net_ne2000.o \ + net_wd8003.o SNDOBJ := sound.o \ openal.o \