aboutsummaryrefslogtreecommitdiff
path: root/src/fake86/i8237.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fake86/i8237.c')
-rwxr-xr-xsrc/fake86/i8237.c133
1 files changed, 133 insertions, 0 deletions
diff --git a/src/fake86/i8237.c b/src/fake86/i8237.c
new file mode 100755
index 0000000..2ad9498
--- /dev/null
+++ b/src/fake86/i8237.c
@@ -0,0 +1,133 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2013 Mike Chambers
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* i8237.c: functions to emulate the Intel 8237 DMA controller.
+ the Sound Blaster emulation functions rely on this! */
+
+#include "config.h"
+#include <stdint.h>
+#include <stdio.h>
+#include <memory.h>
+#include "blaster.h"
+#include "i8237.h"
+
+extern struct blaster_s blaster;
+
+struct dmachan_s dmachan[4];
+uint8_t flipflop = 0;
+
+extern void set_port_write_redirector (uint16_t startport, uint16_t endport, void *callback);
+extern void set_port_read_redirector (uint16_t startport, uint16_t endport, void *callback);
+extern uint8_t read86 (uint32_t addr32);
+
+extern uint8_t RAM[0x100000];
+uint8_t read8237 (uint8_t channel) {
+ uint8_t ret;
+ if (dmachan[channel].masked) return (128);
+ if (dmachan[channel].autoinit && (dmachan[channel].count > dmachan[channel].reload) ) dmachan[channel].count = 0;
+ if (dmachan[channel].count > dmachan[channel].reload) return (128);
+ //if (dmachan[channel].direction) ret = RAM[dmachan[channel].page + dmachan[channel].addr + dmachan[channel].count];
+ // else ret = RAM[dmachan[channel].page + dmachan[channel].addr - dmachan[channel].count];
+ if (dmachan[channel].direction == 0) ret = RAM[dmachan[channel].page + dmachan[channel].addr + dmachan[channel].count];
+ else ret = RAM[dmachan[channel].page + dmachan[channel].addr - dmachan[channel].count];
+ dmachan[channel].count++;
+ return (ret);
+}
+
+void out8237 (uint16_t addr, uint8_t value) {
+ uint8_t channel;
+#ifdef DEBUG_DMA
+ printf ("out8237(0x%X, %X);\n", addr, value);
+#endif
+ switch (addr) {
+ case 0x2: //channel 1 address register
+ if (flipflop == 1) dmachan[1].addr = (dmachan[1].addr & 0x00FF) | ( (uint32_t) value << 8);
+ else dmachan[1].addr = (dmachan[1].addr & 0xFF00) | value;
+#ifdef DEBUG_DMA
+ if (flipflop == 1) printf ("[NOTICE] DMA channel 1 address register = %04X\n", dmachan[1].addr);
+#endif
+ flipflop = ~flipflop & 1;
+ break;
+ case 0x3: //channel 1 count register
+ if (flipflop == 1) dmachan[1].reload = (dmachan[1].reload & 0x00FF) | ( (uint32_t) value << 8);
+ else dmachan[1].reload = (dmachan[1].reload & 0xFF00) | value;
+ if (flipflop == 1) {
+ if (dmachan[1].reload == 0) dmachan[1].reload = 65536;
+ dmachan[1].count = 0;
+#ifdef DEBUG_DMA
+ printf ("[NOTICE] DMA channel 1 reload register = %04X\n", dmachan[1].reload);
+#endif
+ }
+ flipflop = ~flipflop & 1;
+ break;
+ case 0xA: //write single mask register
+ channel = value & 3;
+ dmachan[channel].masked = (value >> 2) & 1;
+#ifdef DEBUG_DMA
+ printf ("[NOTICE] DMA channel %u masking = %u\n", channel, dmachan[channel].masked);
+#endif
+ break;
+ case 0xB: //write mode register
+ channel = value & 3;
+ dmachan[channel].direction = (value >> 5) & 1;
+ dmachan[channel].autoinit = (value >> 4) & 1;
+ dmachan[channel].writemode = (value >> 2) & 1; //not quite accurate
+#ifdef DEBUG_DMA
+ printf ("[NOTICE] DMA channel %u write mode reg: direction = %u, autoinit = %u, write mode = %u\n",
+ channel, dmachan[channel].direction, dmachan[channel].autoinit, dmachan[channel].writemode);
+#endif
+ break;
+ case 0xC: //clear byte pointer flip-flop
+#ifdef DEBUG_DMA
+ printf ("[NOTICE] DMA cleared byte pointer flip-flop\n");
+#endif
+ flipflop = 0;
+ break;
+ case 0x83: //DMA channel 1 page register
+ dmachan[1].page = (uint32_t) value << 16;
+#ifdef DEBUG_DMA
+ printf ("[NOTICE] DMA channel 1 page base = %05X\n", dmachan[1].page);
+#endif
+ break;
+ }
+}
+
+uint8_t in8237 (uint16_t addr) {
+#ifdef DEBUG_DMA
+ printf ("in8237(0x%X);\n", addr);
+#endif
+ switch (addr) {
+ case 3:
+ if (flipflop == 1) return(dmachan[1].reload >> 8);
+ else return(dmachan[1].reload);
+ flipflop = ~flipflop & 1;
+ break;
+ }
+ return (0);
+}
+
+void init8237() {
+ memset (dmachan, 0, sizeof (dmachan) );
+
+ set_port_write_redirector (0x00, 0x0F, &out8237);
+ set_port_read_redirector (0x00, 0x0F, &in8237);
+
+ set_port_write_redirector (0x80, 0x8F, &out8237);
+ set_port_read_redirector (0x80, 0x8F, &in8237);
+}