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 \