From f48c50f4ba7ac469fa79ed6119ac19f7376b79fd Mon Sep 17 00:00:00 2001 From: TC1995 Date: Mon, 20 Jan 2025 03:26:49 +0100 Subject: [PATCH 1/6] The delayed video changes of the night (January 20th, 2025) Generic SVGA layer: Added function pointers of the banked mapping for use with add-on cards with their own mapping when the VGA card banked mapping is not active or viceversa (e.g.: XGA). XGA-1/2: 1. Reimplemented Area Fill and Boundary Mode as best as possible. 2. Fixed conflicts with banked mapping with VGA clones. 3. Fixed inverted colors (again) on accelerated 16bpp mode under OS/2. Video7 with ATI 8514/A add-on. Added a workaround (BIOS issue? I don't know) that disables 8514/A mode and reenables VGA mode when needed. Fixes screen freezes and polling issues with various drivers for Windows and others. --- src/include/86box/vid_svga.h | 8 + src/video/vid_cl54xx.c | 8 + src/video/vid_ht216.c | 27 +++- src/video/vid_paradise.c | 22 +-- src/video/vid_svga.c | 21 ++- src/video/vid_xga.c | 276 ++++++++++++++++++++--------------- 6 files changed, 219 insertions(+), 143 deletions(-) diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index d38b7614b..2b26df2f3 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -202,6 +202,14 @@ typedef struct svga_t { void (*vblank_start)(struct svga_t *svga); + void (*write)(uint32_t addr, uint8_t val, void *priv); + void (*writew)(uint32_t addr, uint16_t val, void *priv); + void (*writel)(uint32_t addr, uint32_t val, void *priv); + + uint8_t (*read)(uint32_t addr, void *priv); + uint16_t (*readw)(uint32_t addr, void *priv); + uint32_t (*readl)(uint32_t addr, void *priv); + void (*ven_write)(struct svga_t *svga, uint8_t val, uint32_t addr); float (*getclock)(int clock, void *priv); float (*getclock8514)(int clock, void *priv); diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index bc54d0d7c..08a8c7677 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -4403,7 +4403,13 @@ gd54xx_init(const device_t *info) if ((vram == 1) || (vram >= 256 && vram <= 1024)) svga->decode_mask = gd54xx->vram_mask; + svga->read = gd54xx_read; + svga->readw = gd54xx_readw; + svga->write = gd54xx_write; + svga->writew = gd54xx_writew; if (gd54xx->bit32) { + svga->readl = gd54xx_readl; + svga->writel = gd54xx_writel; mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); mem_mapping_add(&gd54xx->mmio_mapping, 0, 0, @@ -4423,6 +4429,8 @@ gd54xx_init(const device_t *info) gd5480_vgablt_write, gd5480_vgablt_writew, gd5480_vgablt_writel, NULL, MEM_MAPPING_EXTERNAL, gd54xx); } else { + svga->readl = NULL; + svga->writel = NULL; mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, NULL, gd54xx_write, gd54xx_writew, NULL); mem_mapping_add(&gd54xx->mmio_mapping, 0, 0, diff --git a/src/video/vid_ht216.c b/src/video/vid_ht216.c index a249631ee..f349864df 100644 --- a/src/video/vid_ht216.c +++ b/src/video/vid_ht216.c @@ -33,9 +33,12 @@ #include <86box/rom.h> #include <86box/device.h> #include <86box/video.h> +#include <86box/vid_8514a.h> #include <86box/vid_xga.h> #include <86box/vid_svga.h> #include <86box/vid_svga_render.h> +#include <86box/vid_ati_eeprom.h> +#include <86box/vid_ati_mach8.h> #include <86box/plat_fallthrough.h> #include <86box/plat_unused.h> @@ -425,9 +428,8 @@ ht216_out(uint16_t addr, uint8_t val, void *priv) svga->banked_mask = 0xffff; } - if (svga->gdcaddr <= 8) { + if (svga->gdcaddr <= 8) svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) && svga->chain4 && svga->packed_chain4; - } break; case 0x3D4: @@ -625,7 +627,9 @@ ht216_remap(ht216_t *ht216) void ht216_recalctimings(svga_t *svga) { - ht216_t *ht216 = (ht216_t *) svga->priv; + ht216_t *ht216 = (ht216_t *) svga->priv; + ibm8514_t *dev = (ibm8514_t *) svga->dev8514; + mach_t *mach = (mach_t *) svga->ext8514; int high_res_256 = 0; @@ -672,10 +676,16 @@ ht216_recalctimings(svga_t *svga) if (!svga->scrblank && svga->attr_palette_enable) { if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ - if (svga->seqregs[1] & 8) /*40 column*/ { + if (svga->seqregs[1] & 8) /*40 column*/ svga->render = svga_render_text_40; - } else { + else svga->render = svga_render_text_80; + + if (ibm8514_active && (svga->dev8514 != NULL)) { + if (svga->ext8514 != NULL) { + if (!(dev->accel.advfunc_cntl & 0x01) && !(mach->accel.clock_sel & 0x01)) /*FIXME: Possibly a BIOS bug within the V7 chips when it's used with a 8514/A card?*/ + dev->on &= ~0x01; + } } } else { if (svga->crtc[0x17] == 0xeb) { @@ -1576,10 +1586,17 @@ ht216_init(const device_t *info, uint32_t mem_size, int has_rom) if (has_rom == 4) svga->ramdac = device_add(&sc11484_nors2_ramdac_device); + svga->read = ht216_read; + svga->readw = NULL; + svga->readl = NULL; + svga->write = ht216_write; + svga->writew = ht216_writew; if ((info->flags & DEVICE_VLB) || (info->flags & DEVICE_MCA)) { + svga->writel = ht216_writel; mem_mapping_set_handler(&svga->mapping, ht216_read, NULL, NULL, ht216_write, ht216_writew, ht216_writel); mem_mapping_add(&ht216->linear_mapping, 0, 0, ht216_read_linear, NULL, NULL, ht216_write_linear, ht216_writew_linear, ht216_writel_linear, NULL, MEM_MAPPING_EXTERNAL, svga); } else { + svga->writel = NULL; mem_mapping_set_handler(&svga->mapping, ht216_read, NULL, NULL, ht216_write, ht216_writew, NULL); mem_mapping_add(&ht216->linear_mapping, 0, 0, ht216_read_linear, NULL, NULL, ht216_write_linear, ht216_writew_linear, NULL, NULL, MEM_MAPPING_EXTERNAL, svga); } diff --git a/src/video/vid_paradise.c b/src/video/vid_paradise.c index bf038eb32..27e98d32d 100644 --- a/src/video/vid_paradise.c +++ b/src/video/vid_paradise.c @@ -362,11 +362,6 @@ paradise_write(uint32_t addr, uint8_t val, void *priv) uint32_t prev_addr; uint32_t prev_addr2; - if (!(svga->attrregs[0x10] & 0x40)) { - svga_write(addr, val, svga); - return; - } - addr = (addr & 0x7fff) + paradise->write_bank[(addr >> 15) & 3]; /*Could be done in a better way but it works.*/ @@ -400,11 +395,6 @@ paradise_writew(uint32_t addr, uint16_t val, void *priv) uint32_t prev_addr; uint32_t prev_addr2; - if (!(svga->attrregs[0x10] & 0x40)) { - svga_writew(addr, val, svga); - return; - } - addr = (addr & 0x7fff) + paradise->write_bank[(addr >> 15) & 3]; /*Could be done in a better way but it works.*/ @@ -438,9 +428,6 @@ paradise_read(uint32_t addr, void *priv) uint32_t prev_addr; uint32_t prev_addr2; - if (!(svga->attrregs[0x10] & 0x40)) - return svga_read(addr, svga); - addr = (addr & 0x7fff) + paradise->read_bank[(addr >> 15) & 3]; /*Could be done in a better way but it works.*/ @@ -474,9 +461,6 @@ paradise_readw(uint32_t addr, void *priv) uint32_t prev_addr; uint32_t prev_addr2; - if (!(svga->attrregs[0x10] & 0x40)) - return svga_readw(addr, svga); - addr = (addr & 0x7fff) + paradise->read_bank[(addr >> 15) & 3]; /*Could be done in a better way but it works.*/ @@ -550,6 +534,12 @@ paradise_init(const device_t *info, uint32_t memory) break; } + svga->read = paradise_read; + svga->readw = paradise_readw; + svga->readl = NULL; + svga->write = paradise_write; + svga->writew = paradise_writew; + svga->writel = NULL; mem_mapping_set_handler(&svga->mapping, paradise_read, paradise_readw, NULL, paradise_write, paradise_writew, NULL); mem_mapping_set_p(&svga->mapping, paradise); diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 6a91713fb..e6201e4bf 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -984,7 +984,7 @@ svga_recalctimings(svga_t *svga) svga_log("IBM 8514/A poll.\n"); timer_set_callback(&svga->timer, ibm8514_poll); } else { - svga_log("SVGA Poll.\n"); + svga_log("SVGA poll enabled.\n"); timer_set_callback(&svga->timer, svga_poll); } } @@ -1081,6 +1081,7 @@ svga_poll(void *priv) } } + svga_log("SVGA Poll.\n"); if (!svga->linepos) { if (svga->displine == ((svga->hwcursor_latch.y < 0) ? 0 : svga->hwcursor_latch.y) && svga->hwcursor_latch.ena) { svga->hwcursor_on = svga->hwcursor_latch.cur_ysize - svga->hwcursor_latch.yoff; @@ -1406,16 +1407,34 @@ svga_init(const device_t *info, svga_t *svga, void *priv, int memsize, svga->ksc5601_english_font_type = 0; if ((info->flags & DEVICE_PCI) || (info->flags & DEVICE_VLB) || (info->flags & DEVICE_MCA)) { + svga->read = svga_read; + svga->readw = svga_readw; + svga->readl = svga_readl; + svga->write = svga_write; + svga->writew = svga_writew; + svga->writel = svga_writel; mem_mapping_add(&svga->mapping, 0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL, MEM_MAPPING_EXTERNAL, svga); } else if ((info->flags & DEVICE_ISA) && (info->flags & DEVICE_AT)) { + svga->read = svga_read; + svga->readw = svga_readw; + svga->readl = NULL; + svga->write = svga_write; + svga->writew = svga_writew; + svga->writel = NULL; mem_mapping_add(&svga->mapping, 0xa0000, 0x20000, svga_read, svga_readw, NULL, svga_write, svga_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, svga); } else { + svga->read = svga_read; + svga->readw = NULL; + svga->readl = NULL; + svga->write = svga_write; + svga->writew = NULL; + svga->writel = NULL; mem_mapping_add(&svga->mapping, 0xa0000, 0x20000, svga_read, NULL, NULL, svga_write, NULL, NULL, diff --git a/src/video/vid_xga.c b/src/video/vid_xga.c index 3df43a29c..852ff6273 100644 --- a/src/video/vid_xga.c +++ b/src/video/vid_xga.c @@ -188,7 +188,7 @@ xga_updatemapping(svga_t *svga) mem_mapping_disable(&xga->linear_mapping); break; default: - xga_log("XGA: Extended Graphics mode.\n"); + xga_log("XGA: Extended Graphics mode, ap=%d.\n", xga->aperture_cntl); switch (xga->aperture_cntl) { case 0: xga_log("XGA: No 64KB aperture: 1MB=%x, 4MB=%x, SVGA Mapping Base=%x.\n", xga->base_addr_1mb, xga->linear_base, svga->mapping.base); @@ -201,7 +201,7 @@ xga_updatemapping(svga_t *svga) } else mem_mapping_disable(&xga->linear_mapping); - mem_mapping_set_handler(&svga->mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + mem_mapping_set_handler(&svga->mapping, svga->read, svga->readw, svga->readl, svga->write, svga->writew, svga->writel); switch (svga->gdcreg[6] & 0xc) { case 0x0: /*128k at A0000*/ mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); @@ -439,9 +439,9 @@ xga_ext_out_reg(xga_t *xga, svga_t *svga, uint8_t idx, uint8_t val) break; case 0x51: - xga_log("Reg51 write = %02x.\n", val); + xga_log("Reg51 write=%02x.\n", val & 0x07); xga->disp_cntl_2 = val; - xga->on = ((val & 7) >= 2); + xga->on = ((val & 0x07) >= 0x02); svga_recalctimings(svga); break; @@ -535,9 +535,11 @@ xga_ext_outb(uint16_t addr, uint8_t val, void *priv) xga_log("[%04X:%08X]: EXT OUTB = %02x, val = %02x\n", CS, cpu_state.pc, addr, val); switch (addr & 0x0f) { case 0: + xga_log("[%04X:%08X]: EXT OUTB = %02x, val = %02x\n", CS, cpu_state.pc, addr, val); xga->op_mode = val; break; case 1: + xga_log("[%04X:%08X]: EXT OUTB = %02x, val = %02x\n", CS, cpu_state.pc, addr, val); xga->aperture_cntl = val & 3; xga_updatemapping(svga); break; @@ -579,6 +581,7 @@ xga_ext_outb(uint16_t addr, uint8_t val, void *priv) break; default: + xga_log("[%04X:%08X]: EXT OUTB = %02x, val = %02x\n", CS, cpu_state.pc, addr, val); break; } } @@ -807,6 +810,7 @@ xga_ext_inb(uint16_t addr, void *priv) break; default: + xga_log("[%04X:%08X]: EXT INB = %02x, ret = %02x.\n\n", CS, cpu_state.pc, addr, ret); break; } @@ -933,6 +937,32 @@ xga_accel_read_pattern_map_pixel(svga_t *svga, int x, int y, uint32_t base, int return px; } +static uint32_t +xga_accel_read_area_map_pixel(svga_t *svga, int x, int y, uint32_t base, int width) +{ + const xga_t *xga = (xga_t *) svga->xga; + uint32_t addr = base; + int bits; + uint8_t byte; + uint8_t px; + int skip = 0; + + if ((addr < xga->linear_base) || (addr > (xga->linear_base + 0xfffff))) + skip = 1; + + addr += (y * (width >> 3)); + addr += (x >> 3); + if (!skip) { + READ(addr, byte); + } else + byte = mem_readb_phys(addr); + + bits = 7 - (x & 7); + + px = (byte >> bits) & 1; + return px; +} + static uint32_t xga_accel_read_map_pixel(svga_t *svga, int x, int y, int map, uint32_t base, int width) { @@ -971,6 +1001,7 @@ xga_accel_read_map_pixel(svga_t *svga, int x, int y, int map, uint32_t base, int } else byte = mem_readb_phys(addr); + xga_log("4bpp read: OPMODEBIG=%02x, SRC Map=%02x, DST Map=%02x, AccessMode=%02x, SRCPIX=%02x, DSTPIX=%02x, wordpix=%04x, x=%d, y=%d, skip=%d.\n", xga->op_mode & 0x08, (xga->accel.px_map_format[xga->accel.src_map] & 0x0f), (xga->accel.px_map_format[xga->accel.dst_map] & 0x0f), xga->access_mode & 0x0f, xga->accel.src_map, xga->accel.dst_map, byte, x, y, skip); return byte; case 3: /*8-bit*/ addr += (y * width); @@ -984,19 +1015,15 @@ xga_accel_read_map_pixel(svga_t *svga, int x, int y, int map, uint32_t base, int case 4: /*16-bit*/ addr += (y * (width << 1)); addr += (x << 1); - if (xga->access_mode & 0x08) { - if (!skip) { - READW(addr, byte); - } else - byte = mem_readw_phys(addr); - } else { - if (!skip) { - READW(addr, byte); - } else { - byte = mem_readw_phys(addr); - if ((xga->access_mode & 0x07) == 0x04) - byte = ((byte & 0xff00) >> 8) | ((byte & 0x00ff) << 8); - } + + if (!skip) { + READW(addr, byte); + } else { + byte = mem_readw_phys(addr); + if ((xga->access_mode & 0x07) == 0x04) + byte = ((byte & 0xff00) >> 8) | ((byte & 0x00ff) << 8); + else if (xga->access_mode & 0x08) + byte = ((byte & 0xff00) >> 8) | ((byte & 0x00ff) << 8); } return byte; @@ -1081,17 +1108,14 @@ xga_accel_write_map_pixel(svga_t *svga, int x, int y, int map, uint32_t base, ui case 4: /*16-bit*/ addr += (y * width << 1); addr += (x << 1); - if (xga->access_mode & 0x08) { - if (!skip) { - WRITEW(addr, pixel); - } + + if (!skip) { + WRITEW(addr, pixel); } else { - if (!skip) { - WRITEW(addr, pixel); - } else { - if ((xga->access_mode & 0x07) == 0x04) - pixel = ((pixel & 0xff00) >> 8) | ((pixel & 0x00ff) << 8); - } + if ((xga->access_mode & 0x07) == 0x04) + pixel = ((pixel & 0xff00) >> 8) | ((pixel & 0x00ff) << 8); + else if (xga->access_mode & 0x08) + pixel = ((pixel & 0xff00) >> 8) | ((pixel & 0x00ff) << 8); } mem_writew_phys(addr, pixel); break; @@ -1237,12 +1261,11 @@ xga_line_draw_write(svga_t *svga) uint32_t srcbase = xga->accel.px_map_base[xga->accel.src_map]; int y = xga->accel.blt_width; int x = 0; + int draw_pixel = 0; int16_t dx; int16_t dy; int16_t cx; int16_t cy; - int err = xga->accel.bres_err_term; - int draw_pixel = 0; cx = xga->accel.src_map_x & 0xfff; cy = xga->accel.src_map_y & 0xfff; @@ -1256,38 +1279,57 @@ xga_line_draw_write(svga_t *svga) dy |= ~0x17ff; if ((xga->accel.command & 0x30) == 0x30) - xga_log("Line Draw Write: BLTWIDTH=%d, BLTHEIGHT=%d, FRGDCOLOR=%04x, XDIR=%i, YDIR=%i, steep=%s, ERR=%04x.\n", xga->accel.blt_width, xga->accel.blt_height, xga->accel.frgd_color & 0xffff, xdir, ydir, (xga->accel.octant & 0x01) ? "0" : "1", err); - + xga_log("Line Draw Write Fill: DX=%d, DY=%d, BLTWIDTH=%d, BLTHEIGHT=%d, FRGDCOLOR=%04x, negative XDIR=%i, negative YDIR=%i, YMAJOR=%d, ERR=%d, BRESK2=%d, BRESK1=%d, mask=%02x.\n", dx, dy, xga->accel.blt_width, xga->accel.blt_height, xga->accel.frgd_color & 0xffff, (xga->accel.octant & 0x04), (xga->accel.octant & 0x02), (xga->accel.octant & 0x01), xga->accel.bres_err_term, xga->accel.bres_k2, xga->accel.bres_k1, xga->accel.command & 0xc0); if (xga->accel.pat_src == 8) { if ((xga->accel.command & 0x30) == 0x30) { while (y >= 0) { draw_pixel = 0; - if (xga->accel.octant & 0x01) { - if (xga->accel.octant & 0x02) { /*Bottom-to-Top*/ + if (xga->accel.octant & 0x01) { /*Y Major*/ + if (xga->accel.octant & 0x02) { /*Bottom to Top*/ if (x) draw_pixel = 1; - } else { /*Top-to-Bottom*/ + } else { /*Top to Bottom*/ if (y) draw_pixel = 1; } - } else if (!(xga->accel.octant & 0x04) && (err < (xga->accel.bres_k2 + xga->accel.bres_k1))) /*X+*/ - draw_pixel = 1; - else if ((xga->accel.octant & 0x04) && (err >= 0)) /*X-*/ - draw_pixel = 1; - - if (xga->accel.command & 0xc0) { - if ((dx >= xga->accel.mask_map_origin_x_off) && (dx <= ((xga->accel.px_map_width[0] & 0xfff) + xga->accel.mask_map_origin_x_off)) && (dy >= xga->accel.mask_map_origin_y_off) && (dy <= ((xga->accel.px_map_height[0] & 0xfff) + xga->accel.mask_map_origin_y_off))) { - if (draw_pixel) { - src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, cx, cy, xga->accel.src_map, srcbase, xga->accel.px_map_width[xga->accel.src_map] + 1) : xga->accel.frgd_color; - dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, xga->accel.px_map_width[xga->accel.dst_map] + 1); - - if ((xga->accel.cc_cond == 4) || ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { - ROP(1, dest_dat, src_dat); - xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1); + } else { /*X Major*/ + if (xga->accel.octant & 0x04) { /*Right to Left*/ + if (xga->accel.bres_err_term >= 0) { + if (xga->accel.octant & 0x02) { /*Bottom to Top*/ + if (x) + draw_pixel = 1; + } else { /*Top to Bottom*/ + if (y) + draw_pixel = 1; } } + } else { /*Left to Right*/ + if (xga->accel.bres_err_term < (xga->accel.bres_k1 + xga->accel.bres_k2)) { + if (xga->accel.octant & 0x02) { /*Bottom to Top*/ + if (x) + draw_pixel = 1; + } else { /*Top to Bottom*/ + if (y) + draw_pixel = 1; + } + } + } + } + + xga_log("Draw Boundary: DX=%d, DY=%d, wrt_pix=%d, ymajor=%d, bottomtotop=%x, len=%d, err=%d, frgdmix=%02x.\n", dx, dy, draw_pixel, xga->accel.octant & 0x01, xga->accel.octant & 0x02, y, xga->accel.bres_err_term, xga->accel.frgd_mix & 0x1f); + if (xga->accel.command & 0xc0) { + if ((dx >= xga->accel.mask_map_origin_x_off) && (dx <= ((xga->accel.px_map_width[0] & 0xfff) + xga->accel.mask_map_origin_x_off)) && (dy >= xga->accel.mask_map_origin_y_off) && (dy <= ((xga->accel.px_map_height[0] & 0xfff) + xga->accel.mask_map_origin_y_off)) && draw_pixel) { + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, cx, cy, xga->accel.src_map, srcbase, xga->accel.px_map_width[xga->accel.src_map] + 1) : xga->accel.frgd_color; + dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, xga->accel.px_map_width[xga->accel.dst_map] + 1); + + if ((xga->accel.cc_cond == 4) || ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + old_dest_dat = dest_dat; + ROP(1, dest_dat, src_dat); + dest_dat = (dest_dat & plane_mask) | (old_dest_dat & ~plane_mask); + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1); + } } } else { if (draw_pixel) { @@ -1295,7 +1337,9 @@ xga_line_draw_write(svga_t *svga) dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, xga->accel.px_map_width[xga->accel.dst_map] + 1); if ((xga->accel.cc_cond == 4) || ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + old_dest_dat = dest_dat; ROP(1, dest_dat, src_dat); + dest_dat = (dest_dat & plane_mask) | (old_dest_dat & ~plane_mask); xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, xga->accel.px_map_width[xga->accel.dst_map] + 1); } } @@ -1310,28 +1354,28 @@ xga_line_draw_write(svga_t *svga) else dy++; - if (err >= 0) { - err += xga->accel.bres_k2; + if (xga->accel.bres_err_term >= 0) { + xga->accel.bres_err_term += xga->accel.bres_k2; if (xga->accel.octant & 0x04) dx--; else dx++; } else - err += xga->accel.bres_k1; + xga->accel.bres_err_term += xga->accel.bres_k1; } else { if (xga->accel.octant & 0x04) dx--; else dx++; - if (err >= 0) { - err += xga->accel.bres_k2; + if (xga->accel.bres_err_term >= 0) { + xga->accel.bres_err_term += xga->accel.bres_k2; if (xga->accel.octant & 0x02) dy--; else dy++; } else - err += xga->accel.bres_k1; + xga->accel.bres_err_term += xga->accel.bres_k1; } x++; y--; @@ -1384,28 +1428,28 @@ xga_line_draw_write(svga_t *svga) else dy++; - if (err >= 0) { - err += xga->accel.bres_k2; + if (xga->accel.bres_err_term >= 0) { + xga->accel.bres_err_term += xga->accel.bres_k2; if (xga->accel.octant & 0x04) dx--; else dx++; } else - err += xga->accel.bres_k1; + xga->accel.bres_err_term += xga->accel.bres_k1; } else { if (xga->accel.octant & 0x04) dx--; else dx++; - if (err >= 0) { - err += xga->accel.bres_k2; + if (xga->accel.bres_err_term >= 0) { + xga->accel.bres_err_term += xga->accel.bres_k2; if (xga->accel.octant & 0x02) dy--; else dy++; } else - err += xga->accel.bres_k1; + xga->accel.bres_err_term += xga->accel.bres_k1; } y--; x++; @@ -1454,20 +1498,21 @@ xga_bitblt(svga_t *svga) if (xga->accel.dst_map_y >= 0x1800) dy |= ~0x17ff; - xga_log("D(%d,%d), SWH(%d,%d), BLT(%d,%d), dstwidth=%d.\n", dx, dy, xga->accel.x, xga->accel.y, srcwidth, srcheight, dstwidth); + xga_log("D(%d,%d), SWH(%d,%d), BLT(%d,%d), dstwidth=%d, frgdcol=%04x, bkgdcol=%04x.\n", dx, dy, xga->accel.x, xga->accel.y, srcwidth, srcheight, dstwidth, frgdcol, bkgdcol); xga->accel.pattern = 0; xga->accel.filling = 0; - xga_log("XGA bitblt linear endian reverse=%d, access_mode=%x, octanty=%d, src command = %08x, " + xga_log("XGA bitblt access_mode=%x, octanty=%d, src command=%08x, " "pxsrcmap=%x, pxpatmap=%x, pxdstmap=%x, srcmap=%d, patmap=%d, dstmap=%d, " - "usesrcvramfr=%d, usevrambk=%d.\n", - xga->linear_endian_reverse, xga->access_mode & 0x0f, ydir, xga->accel.command, + "usesrcvramfr=%d, usevrambk=%d, frgdcol=%04x, bkgdcol=%04x, bgmix=%02x, fgmix=%02x.\n", + xga->access_mode & 0x0f, ydir, xga->accel.command, xga->accel.px_map_format[xga->accel.src_map] & 0x0f, xga->accel.px_map_format[xga->accel.pat_src] & 0x0f, xga->accel.px_map_format[xga->accel.dst_map] & 0x0f, xga->accel.src_map, xga->accel.pat_src, - xga->accel.dst_map, ((xga->accel.command >> 28) & 3), ((xga->accel.command >> 30) & 3)); + xga->accel.dst_map, ((xga->accel.command >> 28) & 3), ((xga->accel.command >> 30) & 3), + frgdcol, bkgdcol, xga->accel.bkgd_mix & 0x1f, xga->accel.frgd_mix & 0x1f); if (xga->accel.pat_src == 8) { if (srcheight == 7) @@ -1593,17 +1638,19 @@ xga_bitblt(svga_t *svga) xga->accel.px_map_width[2], xga->accel.px_map_width[3], bkgdcol); xga_log("Pattern Enabled?=%d, patwidth=%d, patheight=%d, P(%d,%d).\n", xga->accel.pattern, patwidth, patheight, xga->accel.px, xga->accel.py); - if ((((xga->accel.command >> 24) & 0x0f) == 0x0a) && ((xga->accel.bkgd_mix & 0x1f) == 5)) { - while (xga->accel.y >= 0) { - mix = xga_accel_read_pattern_map_pixel(svga, xga->accel.px, xga->accel.py, patbase, patwidth + 1); - if (mix) - xga->accel.filling = !xga->accel.filling; + if (((xga->accel.command >> 24) & 0x0f) == 0x0a) { + if ((xga->accel.bkgd_mix & 0x1f) == 0x05) { + while (xga->accel.y >= 0) { + mix = xga_accel_read_area_map_pixel(svga, xga->accel.px, xga->accel.py, patbase, patwidth + 1); + if (mix) + xga->accel.filling ^= 1; - if (xga->accel.command & 0xc0) { - if ((dx >= xga->accel.mask_map_origin_x_off) && (dx <= ((xga->accel.px_map_width[0] & 0xfff) + xga->accel.mask_map_origin_x_off)) && (dy >= xga->accel.mask_map_origin_y_off) && (dy <= ((xga->accel.px_map_height[0] & 0xfff) + xga->accel.mask_map_origin_y_off))) { - src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1) : frgdcol; - if (xga->accel.filling) { - dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, 1024); + xga_log("Area Fill Command: dx=%d, dy=%d, mix=%x, filling=%x.\n", dx, dy, mix, xga->accel.filling); + + if (xga->accel.command & 0xc0) { + if ((dx >= xga->accel.mask_map_origin_x_off) && (dx <= ((xga->accel.px_map_width[0] & 0xfff) + xga->accel.mask_map_origin_x_off)) && (dy >= xga->accel.mask_map_origin_y_off) && (dy <= ((xga->accel.px_map_height[0] & 0xfff) + xga->accel.mask_map_origin_y_off)) && xga->accel.filling) { + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1) : frgdcol; + dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dstwidth + 1); if ((xga->accel.cc_cond == 4) || ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { old_dest_dat = dest_dat; ROP(1, dest_dat, src_dat); @@ -1612,11 +1659,9 @@ xga_bitblt(svga_t *svga) xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, dstwidth + 1); } } - } - } else { - if ((dx >= 0) && (dx <= dstwidth) && (dy >= 0) && (dy <= dstheight)) { - src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1) : frgdcol; - if (xga->accel.filling) { + } else { + if ((dx >= 0) && (dx <= dstwidth) && (dy >= 0) && (dy <= dstheight) && xga->accel.filling) { + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1) : frgdcol; dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dstwidth + 1); if ((xga->accel.cc_cond == 4) || ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { old_dest_dat = dest_dat; @@ -1627,32 +1672,35 @@ xga_bitblt(svga_t *svga) } } } - } - xga->accel.sx = ((xga->accel.sx + xdir) & srcwidth) | (xga->accel.sx & ~srcwidth); - xga->accel.px++; + xga->accel.sx = ((xga->accel.sx + xdir) & srcwidth) | (xga->accel.sx & ~srcwidth); + xga->accel.px++; - dx++; - xga->accel.x--; - if (xga->accel.x < 0) { - xga->accel.y--; - xga->accel.x = xga->accel.blt_width & 0xfff; + dx++; + xga->accel.x--; + if (xga->accel.x < 0) { + xga->accel.y--; + xga->accel.x = xga->accel.blt_width & 0xfff; - dx = xga->accel.dst_map_x; - if (xga->accel.dst_map_x >= 0x1800) - dx |= ~0x17ff; + dx = xga->accel.dst_map_x; + if (xga->accel.dst_map_x >= 0x1800) + dx |= ~0x17ff; - xga->accel.sx = xga->accel.src_map_x & 0xfff; - xga->accel.px = xga->accel.pat_map_x & 0xfff; + xga->accel.sx = xga->accel.src_map_x & 0xfff; + xga->accel.px = xga->accel.pat_map_x & 0xfff; - xga->accel.sy = ((xga->accel.sy + ydir) & srcheight) | (xga->accel.sy & ~srcheight); - xga->accel.py++; + xga->accel.sy = ((xga->accel.sy + ydir) & srcheight) | (xga->accel.sy & ~srcheight); + xga->accel.py++; - dy++; - xga->accel.filling = 0; + dy++; + xga->accel.filling = 0; - if (xga->accel.y < 0) - return; + if (xga->accel.y < 0) { + xga->accel.dst_map_x = dx; + xga->accel.dst_map_y = dy; + return; + } + } } } } else { @@ -2171,7 +2219,6 @@ exec_command: xga->accel.src_map = ((xga->accel.command >> 20) & 0x0f); xga_log("PATMAP=%x, DSTMAP=%x, SRCMAP=%x.\n", xga->accel.px_map_format[xga->accel.pat_src], xga->accel.px_map_format[xga->accel.dst_map], xga->accel.px_map_format[xga->accel.src_map]); -#ifdef ENABLE_XGA_LOG if (xga->accel.pat_src) xga_log("[%04X:%08X]: Accel Command = %02x, full = %08x, patwidth = %d, " "dstwidth = %d, srcwidth = %d, patheight = %d, dstheight = %d, " @@ -2196,7 +2243,7 @@ exec_command: xga->accel.px_map_format[xga->accel.dst_map] & 0x0f, xga->accel.px_map_format[xga->accel.src_map] & 0x0f, xga->accel.plane_mask); -#endif + switch ((xga->accel.command >> 24) & 0x0f) { case 2: /*Short Stroke Vectors Read */ xga_log("Short Stroke Vectors Read.\n"); @@ -2670,7 +2717,7 @@ xga_write_test(uint32_t addr, uint8_t val, void *priv) xga->vram[addr & xga->vram_mask] = val; xga_log("XGA Linear endian reverse write, val = %02x, addr = %05x, banked mask = %04x, a5test=%d.\n", val, addr, svga->banked_mask, xga->a5_test); } - } else if (xga->aperture_cntl) + } else if (xga->aperture_cntl || (!xga->aperture_cntl && (svga->mapping.base == 0xa0000))) xga->on = 0; } } @@ -2777,9 +2824,8 @@ xga_read_test(uint32_t addr, void *priv) addr += xga->read_bank; return xga->vram[addr & xga->vram_mask]; } - } else if (xga->aperture_cntl) { + } else if (xga->aperture_cntl || (!xga->aperture_cntl && (svga->mapping.base == 0xa0000))) xga->on = 0; - } } return ret; } @@ -2874,7 +2920,7 @@ xga_write_linear(uint32_t addr, uint8_t val, void *priv) svga_t *svga = (svga_t *) priv; xga_t *xga = (xga_t *) svga->xga; - xga_log("WrtieLL XGA=%d.\n", xga->on); + xga_log("WriteLL XGA=%d.\n", xga->on); if (!xga->on) { svga_write_linear(addr, val, svga); return; @@ -2889,13 +2935,6 @@ xga_write_linear(uint32_t addr, uint8_t val, void *priv) cycles -= svga->monitor->mon_video_timing_write_b; - if (!(xga->access_mode & 0x08)) { - if ((xga->access_mode & 0x07) == 0x04) { - if ((xga->accel.px_map_format[xga->accel.dst_map] & 0x07) == 0x04) - addr ^= 1; - } - } - xga->changedvram[(addr & xga->vram_mask) >> 12] = svga->monitor->mon_changeframecount; xga->vram[addr & xga->vram_mask] = val; } @@ -2951,14 +2990,9 @@ xga_read_linear(uint32_t addr, void *priv) cycles -= svga->monitor->mon_video_timing_read_b; - if (!(xga->access_mode & 0x08)) { - if ((xga->access_mode & 0x07) == 0x04) { - if ((xga->accel.px_map_format[xga->accel.dst_map] & 0x07) == 0x04) - addr ^= 1; - } - } + ret = xga->vram[addr & xga->vram_mask]; - return xga->vram[addr & xga->vram_mask]; + return ret; } static uint16_t @@ -3234,7 +3268,7 @@ xga_mca_reset(void *priv) svga_t *svga = (svga_t *) priv; xga_log("MCA Reset.\n"); - mem_mapping_set_handler(&svga->mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + mem_mapping_set_handler(&svga->mapping, svga->read, svga->readw, svga->readl, svga->write, svga->writew, svga->writel); xga_mca_write(0x102, 0, svga); } @@ -3250,7 +3284,7 @@ xga_reset(void *priv) xga->on = 0; xga->a5_test = 0; - mem_mapping_set_handler(&svga->mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + mem_mapping_set_handler(&svga->mapping, svga->read, svga->readw, svga->readl, svga->write, svga->writew, svga->writel); } static uint8_t From f1a856c8863ea06db030605bc0342f340cbe02f7 Mon Sep 17 00:00:00 2001 From: Ectoplasm Date: Mon, 20 Jan 2025 05:53:40 +0200 Subject: [PATCH 2/6] GlaBIOS for Vendex HeadStart Turbo 888-XT --- src/machine/m_xt.c | 53 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index ef3a84e24..9f232ac95 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -919,18 +919,63 @@ machine_xt_pc500_init(const machine_t *model) return ret; } +static const device_config_t vendex_config[] = { + // clang-format off + { + .name = "bios", + .description = "BIOS Version", + .type = CONFIG_BIOS, + .default_string = "vendex", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .bios = { + { .name = "Bios 2.03C", .internal_name = "vendex", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 16384, .files = { "roms/machines/vendex/Vendex Turbo 888 XT - ROM BIOS - VER 2.03C.bin", "" } }, + // GlaBIOS for Juko ST + { .name = "GlaBIOS 0.2.5 (8088)", .internal_name = "glabios_025_8088", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 16384, .files = { "roms/machines/glabios/GLABIOS_0.2.5_8TV.ROM", "" } }, + { .name = "GlaBIOS 0.2.5 (V20)", .internal_name = "glabios_025_v20", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 16384, .files = { "roms/machines/glabios/GLABIOS_0.2.5_VTV.ROM", "" } }, + { .files_no = 0 } + }, + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t vendex_device = { + .name = "Vendex 888T Devices", + .internal_name = "vendex_device", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = vendex_config +}; + int machine_xt_vendex_init(const machine_t *model) { - int ret; + int ret = 0; + const char *fn; - ret = bios_load_linear("roms/machines/vendex/Vendex Turbo 888 XT - ROM BIOS - VER 2.03C.bin", - 0x000fc000, 16384, 0); + /* No ROMs available. */ + if (!device_available(model->device)) + return ret; + + device_context(model->device); + fn = device_get_bios_file(model->device, device_get_config_bios("bios"), 0); + ret = bios_load_linear(fn, 0x000fc000, 16384, 0); + device_context_restore(); if (bios_only || !ret) return ret; - /* On-board FDC cannot be disabled */ machine_xt_clone_init(model, 1); device_add(&vendex_xt_rtc_onboard_device); From ce390fb9cde6b5f3fadec433fad176d2c0b39368 Mon Sep 17 00:00:00 2001 From: Ectoplasm Date: Mon, 20 Jan 2025 05:55:03 +0200 Subject: [PATCH 3/6] GlaBIOS for Vendex HeadStart Turbo 888-XT --- src/machine/machine_table.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index cafbe514d..f2fb53a6f 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -65,6 +65,7 @@ extern const device_t ibmat_device; extern const device_t ibmxt286_device; extern const device_t pb450_device; extern const device_t jukopc_device; +extern const device_t vendex_device; const machine_filter_t machine_types[] = { { "None", MACHINE_TYPE_NONE }, @@ -1696,7 +1697,7 @@ const machine_t machines[] = { .kbc_p1 = 0xff, .gpio = 0xffffffff, .gpio_acpi = 0xffffffff, - .device = NULL, + .device = &vendex_device, .fdc_device = NULL, .sio_device = NULL, .vid_device = NULL, From 0be045b3cff89cd27b019700b782a1ad77643ccd Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Mon, 20 Jan 2025 12:51:27 -0300 Subject: [PATCH 4/6] AD1848: Fix additional data format unlocking which has been wrong this whole time --- src/sound/snd_ad1848.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index a0166c4e5..ddf8e61ec 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -273,20 +273,21 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) return; case 12: - if (ad1848->type != AD1848_TYPE_DEFAULT) - ad1848->regs[12] = ((ad1848->regs[12] & 0x0f) + (val & 0xf0)) | 0x80; + if (ad1848->type >= AD1848_TYPE_CS4248) { + ad1848->regs[12] = 0x80 | (val & 0x70) | (ad1848->regs[12] & 0x0f); + if ((ad1848->type >= AD1848_TYPE_CS4231) && (ad1848->type < AD1848_TYPE_CS4235)) { + if (val & 0x40) + ad1848->fmt_mask |= 0x80; + else + ad1848->fmt_mask &= ~0x80; + } + } return; case 14: ad1848->count = ad1848->regs[15] | (val << 8); break; - case 17: - /* Enable additional data formats on modes 2 and 3 where supported. */ - if ((ad1848->type == AD1848_TYPE_CS4231) || (ad1848->type == AD1848_TYPE_CS4236B)) - ad1848->fmt_mask = (val & 0x40) ? 0xf0 : 0x70; - break; - case 18: case 19: if (ad1848->type >= AD1848_TYPE_CS4236B) { From 3dea388ae4bf7cb8792f9bd6b2f690ebc446de33 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Mon, 20 Jan 2025 13:37:55 -0300 Subject: [PATCH 5/6] CS423x: Fix broken codec on CS4236B --- src/sound/snd_cs423x.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index 0d9af74f2..0a383e13f 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -12,7 +12,7 @@ * * Authors: RichardG, * - * Copyright 2021-2022 RichardG. + * Copyright 2021-2025 RichardG. */ #include #include @@ -386,7 +386,7 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) dev->ram_dl = CRYSTAL_RAM_CMD; /* Update PnP state and resource data. */ - dev->pnp_size = 384; /* we don't know the length */ + dev->pnp_size = (dev->type >= CRYSTAL_CS4236) ? 384 : 256; /* we don't know the length */ cs423x_pnp_enable(dev, 1, 0); } break; @@ -853,12 +853,13 @@ cs423x_init(const device_t *info) dev->type = info->local & 0xff; cs423x_log("CS423x: init(%02X)\n", dev->type); switch (dev->type) { - case CRYSTAL_CS4235: case CRYSTAL_CS4236B: case CRYSTAL_CS4237B: case CRYSTAL_CS4238B: + case CRYSTAL_CS4235: + case CRYSTAL_CS4239: /* Same WSS codec and EEPROM structure. */ - dev->ad1848_type = (dev->type == CRYSTAL_CS4235) ? AD1848_TYPE_CS4235 : AD1848_TYPE_CS4236; + dev->ad1848_type = (dev->type >= CRYSTAL_CS4235) ? AD1848_TYPE_CS4235 : AD1848_TYPE_CS4236B; dev->pnp_offset = 0x4013; /* Different Chip Version and ID registers, which shouldn't be reset by ad1848_init. */ From 40080101313bf30a235610792ac522761b3a94fd Mon Sep 17 00:00:00 2001 From: TC1995 Date: Mon, 20 Jan 2025 19:55:18 +0100 Subject: [PATCH 6/6] Big SCSI bus update of the day, NCR 5380 too (January 20th, 2025) 1. Separate the SCSI bus functions from NCR 5380 into true general purpose SCSI bus functions, allowing use of future legacy scsi controllers. 2. Corrected NCR 5380 chip period for the SCSI controllers based on that chip so that CD-ROM speed is correct enough per speed tests and no more breakage (I hope, report if they are still there, please!) on desyncs. 3. A NCR 5380 software reset involves asserting an IRQ. --- src/include/86box/scsi_device.h | 46 ++++ src/include/86box/scsi_ncr5380.h | 48 +--- src/scsi/scsi_device.c | 334 +++++++++++++++++++++++++++- src/scsi/scsi_ncr5380.c | 371 ++++--------------------------- src/scsi/scsi_ncr53c400.c | 128 +++++------ src/scsi/scsi_t128.c | 89 +++++--- src/sound/snd_pas16.c | 12 +- 7 files changed, 546 insertions(+), 482 deletions(-) diff --git a/src/include/86box/scsi_device.h b/src/include/86box/scsi_device.h index 6fdac5ebd..538a96fac 100644 --- a/src/include/86box/scsi_device.h +++ b/src/include/86box/scsi_device.h @@ -333,6 +333,20 @@ #define BUS_IDLE (1 << 31) +#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 STATE_MESSAGEOUT 7 +#define STATE_MESSAGE_ID 8 + +#define PIO_TX_BUS 0 +#define DMA_IN_TX_BUS 1 +#define DMA_OUT_TX_BUS 2 + #define PHASE_IDLE 0x00 #define PHASE_COMMAND 0x01 #define PHASE_DATA_IN 0x02 @@ -420,6 +434,36 @@ typedef struct scsi_device_t { void (*command_stop)(scsi_common_t *sc); } scsi_device_t; +typedef struct scsi_bus_t { + int tx_mode; + int clear_req; + int wait_data; + int wait_complete; + int bus_out; + int bus_in; + int command_pos; + int command_issued; + int data_pos; + int msgout_pos; + int is_msgout; + int state; + int dma_on_pio_enabled; + uint8_t data; + uint8_t msglun; + uint8_t data_wait; + uint8_t command[16]; + uint8_t msgout[4]; + uint8_t target_id; + uint8_t bus_device; + uint32_t bus_phase; + double period; + double speed; + double divider; + double multi; + void *priv; + void (*timer)(void *priv, double period); +} scsi_bus_t; + /* These are based on the INQUIRY values. */ #define SCSI_NONE 0x0060 #define SCSI_FIXED_DISK 0x0000 @@ -454,6 +498,8 @@ extern void scsi_device_init(void); extern void scsi_reset(void); extern uint8_t scsi_get_bus(void); +extern int scsi_bus_read(scsi_bus_t *scsi_bus); +extern void scsi_bus_update(scsi_bus_t *scsi_bus, int bus); extern void scsi_bus_set_speed(uint8_t bus, double speed); extern double scsi_bus_get_speed(uint8_t bus); diff --git a/src/include/86box/scsi_ncr5380.h b/src/include/86box/scsi_ncr5380.h index 09307fed6..0b8a4efd8 100644 --- a/src/include/86box/scsi_ncr5380.h +++ b/src/include/86box/scsi_ncr5380.h @@ -44,6 +44,9 @@ #define ICR_ACK 0x10 #define ICR_ARB_LOST 0x20 #define ICR_ARB_IN_PROGRESS 0x40 +#define ICR_RST 0x80 +#define ICR_PHASE 0x9e +#define ICR_WRITE 0x9f #define MODE_ARBITRATE 0x01 #define MODE_DMA 0x02 @@ -63,70 +66,33 @@ #define TCR_REQ 0x08 #define TCR_LAST_BYTE_SENT 0x80 - -#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 STATE_MESSAGEOUT 7 -#define STATE_MESSAGE_ID 8 - -#define DMA_IDLE 0 -#define DMA_SEND 1 -#define DMA_INITIATOR_RECEIVE 2 - typedef struct ncr_t { uint8_t icr; uint8_t mode; uint8_t tcr; - uint8_t data_wait; uint8_t isr; uint8_t output_data; - uint8_t target_id; uint8_t tx_data; - uint8_t msglun; uint8_t irq_state; - uint8_t command[20]; - uint8_t msgout[4]; uint8_t bus; - int msgout_pos; - int is_msgout; - - int dma_mode; - int cur_bus; - int bus_in; - int new_phase; - int state; - int clear_req; - int wait_data; - int wait_data_back; - int wait_complete; - int command_pos; - int data_pos; - int irq; double period; void *priv; - void (*dma_mode_ext)(void *priv, void *ext_priv); + void (*dma_mode_ext)(void *priv, void *ext_priv, uint8_t val); int (*dma_send_ext)(void *priv, void *ext_priv); int (*dma_initiator_receive_ext)(void *priv, void *ext_priv); void (*timer)(void *ext_priv, double period); + + scsi_bus_t scsibus; } ncr_t; -extern int ncr5380_cmd_len[8]; - extern void ncr5380_irq(ncr_t *ncr, int set_irq); -extern void ncr5380_set_irq(ncr_t *ncr, int irq); +extern void ncr5380_set_irq(ncr_t *ncr, int irq); extern uint32_t ncr5380_get_bus_host(ncr_t *ncr); -extern void ncr5380_bus_read(ncr_t *ncr); -extern void ncr5380_bus_update(ncr_t *ncr, int bus); extern void ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr); extern uint8_t ncr5380_read(uint16_t port, ncr_t *ncr); diff --git a/src/scsi/scsi_device.c b/src/scsi/scsi_device.c index 4442b2680..33d3fa89a 100644 --- a/src/scsi/scsi_device.c +++ b/src/scsi/scsi_device.c @@ -16,10 +16,14 @@ * Copyright 2016-2018 Miran Grca. * Copyright 2017-2018 Fred N. van Kempen. */ +#include #include #include #include +#include +#include #include +#define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> #include <86box/hdd.h> @@ -29,9 +33,29 @@ #include <86box/plat_unused.h> scsi_device_t scsi_devices[SCSI_BUS_MAX][SCSI_ID_MAX]; - +int scsi_command_length[8] = { 6, 10, 10, 6, 16, 12, 10, 6 }; uint8_t scsi_null_device_sense[18] = { 0x70, 0, SENSE_ILLEGAL_REQUEST, 0, 0, 0, 0, 0, 0, 0, 0, 0, ASC_INV_LUN, 0, 0, 0, 0, 0 }; +#define SET_BUS_STATE(scsi_bus, state) scsi_bus->bus_out = (scsi_bus->bus_out & ~(SCSI_PHASE_MESSAGE_IN)) | (state & (SCSI_PHASE_MESSAGE_IN)) + +#ifdef ENABLE_SCSI_DEVICE_LOG +int scsi_device_do_log = ENABLE_SCSI_DEVICE_LOG; + +static void +scsi_device_log(const char *fmt, ...) +{ + va_list ap; + + if (scsi_device_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define scsi_device_log(fmt, ...) +#endif + static uint8_t scsi_device_target_command(scsi_device_t *dev, uint8_t *cdb) { @@ -189,3 +213,311 @@ scsi_device_init(void) } } } + +int +scsi_device_get_id(uint8_t data) +{ + for (uint8_t c = 0; c < SCSI_ID_MAX; c++) { + if (data & (1 << c)) + return c; + } + + return -1; +} + + +static int +scsi_device_get_msg(uint8_t *msgp, int len) +{ + uint8_t msg = msgp[0]; + if ((msg == 0) || ((msg >= 0x02) && (msg <= 0x1f)) || (msg >= 0x80)) + return 1; + + if ((msg >= 0x20) && (msg <= 0x2f)) + return 2; + + if (len < 2) + return 3; + + return msgp[1]; +} + +int +scsi_bus_read(scsi_bus_t *scsi_bus) +{ + scsi_device_t *dev; + int phase; + + /*Wait processes to handle bus requests*/ + if (scsi_bus->clear_req) { + scsi_bus->clear_req--; + if (!scsi_bus->clear_req) { + scsi_device_log("Prelude to command data\n"); + SET_BUS_STATE(scsi_bus, scsi_bus->bus_phase); + scsi_bus->bus_out |= BUS_REQ; + } + } + + if (scsi_bus->wait_data) { + scsi_bus->wait_data--; + if (!scsi_bus->wait_data) { + dev = &scsi_devices[scsi_bus->bus_device][scsi_bus->target_id]; + SET_BUS_STATE(scsi_bus, scsi_bus->bus_phase); + phase = scsi_bus->bus_out & SCSI_PHASE_MESSAGE_IN; + + switch (phase) { + case SCSI_PHASE_DATA_IN: + scsi_device_log("DataIn.\n"); + scsi_bus->state = STATE_DATAIN; + if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL)) + scsi_bus->data = dev->sc->temp_buffer[scsi_bus->data_pos++]; + + scsi_bus->bus_out = (scsi_bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(scsi_bus->data) | BUS_DBP; + break; + case SCSI_PHASE_DATA_OUT: + if (scsi_bus->bus_phase & BUS_IDLE) { + scsi_device_log("Bus Idle.\n"); + scsi_bus->state = STATE_IDLE; + scsi_bus->bus_out &= ~BUS_BSY; + scsi_bus->timer(scsi_bus->priv, 0.0); + } else { + scsi_device_log("DataOut.\n"); + scsi_bus->state = STATE_DATAOUT; + } + break; + case SCSI_PHASE_STATUS: + scsi_device_log("Status.\n"); + scsi_bus->bus_out |= BUS_REQ; + scsi_bus->state = STATE_STATUS; + scsi_bus->bus_out = (scsi_bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(dev->status) | BUS_DBP; + break; + case SCSI_PHASE_MESSAGE_IN: + scsi_device_log("Message In.\n"); + scsi_bus->state = STATE_MESSAGEIN; + scsi_bus->bus_out = (scsi_bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(0) | BUS_DBP; + break; + case SCSI_PHASE_MESSAGE_OUT: + scsi_device_log("Message Out.\n"); + scsi_bus->bus_out |= BUS_REQ; + scsi_bus->state = STATE_MESSAGEOUT; + scsi_bus->bus_out = (scsi_bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(scsi_bus->target_id >> 5) | BUS_DBP; + break; + default: + break; + } + } + } + + if (scsi_bus->wait_complete) { + scsi_bus->wait_complete--; + if (!scsi_bus->wait_complete) + scsi_bus->bus_out |= BUS_REQ; + } + + return scsi_bus->bus_out; +} + +void +scsi_bus_update(scsi_bus_t *scsi_bus, int bus) +{ + scsi_device_t *dev = &scsi_devices[scsi_bus->bus_device][scsi_bus->target_id]; + double p; + uint8_t sel_data; + int msglen; + + /*Start the SCSI command layer, which will also make the timings*/ + if (bus & BUS_ARB) + scsi_bus->state = STATE_IDLE; + + scsi_device_log("State = %i\n", scsi_bus->state); + + switch (scsi_bus->state) { + case STATE_IDLE: + scsi_bus->clear_req = scsi_bus->wait_data = scsi_bus->wait_complete = 0; + if ((bus & BUS_SEL) && !(bus & BUS_BSY)) { + sel_data = BUS_GETDATA(bus); + + scsi_bus->target_id = scsi_device_get_id(sel_data); + + /*Once the device has been found and selected, mark it as busy*/ + if ((scsi_bus->target_id != (uint8_t) -1) && scsi_device_present(&scsi_devices[scsi_bus->bus_device][scsi_bus->target_id])) { + scsi_bus->bus_out |= BUS_BSY; + scsi_bus->state = STATE_SELECT; + scsi_device_log("Select - target ID = %i, moving to state = %d.\n", scsi_bus->target_id, scsi_bus->state); + } else { + scsi_device_log("Device not found at ID %i, Current Bus BSY=%02x\n", scsi_bus->target_id, scsi_bus->bus_out); + scsi_bus->bus_out = 0; + } + } + break; + case STATE_SELECT: + if (!(bus & BUS_SEL)) { + if (!(bus & BUS_ATN)) { + if ((scsi_bus->target_id != (uint8_t) -1) && scsi_device_present(&scsi_devices[scsi_bus->bus_device][scsi_bus->target_id])) { + scsi_device_log("Device found at ID %i, Current Bus BSY=%02x\n", scsi_bus->target_id, scsi_bus->bus_out); + scsi_bus->state = STATE_COMMAND; + scsi_bus->bus_out = BUS_BSY | BUS_REQ; + scsi_bus->command_pos = 0; + SET_BUS_STATE(scsi_bus, SCSI_PHASE_COMMAND); + } else { + scsi_device_log("Device not found at ID %i again.\n", scsi_bus->target_id); + scsi_bus->state = STATE_IDLE; + scsi_bus->bus_out = 0; + } + } else { + scsi_device_log("Set to SCSI Message Out\n"); + scsi_bus->bus_phase = SCSI_PHASE_MESSAGE_OUT; + scsi_bus->wait_data = 4; + scsi_bus->msgout_pos = 0; + scsi_bus->is_msgout = 1; + } + } + break; + case STATE_COMMAND: + if ((bus & BUS_ACK) && !(scsi_bus->bus_in & BUS_ACK)) { + /*Write command byte to the output data register*/ + scsi_bus->command[scsi_bus->command_pos++] = BUS_GETDATA(bus); + scsi_bus->clear_req = 3; + scsi_bus->bus_phase = scsi_bus->bus_out & SCSI_PHASE_MESSAGE_IN; + scsi_bus->bus_out &= ~BUS_REQ; + + scsi_device_log("Command pos=%i, output data=%02x\n", scsi_bus->command_pos, BUS_GETDATA(bus)); + + if (scsi_bus->command_pos == scsi_command_length[(scsi_bus->command[0] >> 5) & 7]) { + if (scsi_bus->is_msgout) { + scsi_bus->is_msgout = 0; +#if 0 + scsi_bus->command[1] = (scsi_bus->command[1] & 0x1f) | (scsi_bus->msglun << 5); +#endif + } + + /*Reset data position to default*/ + scsi_bus->data_pos = 0; + + dev = &scsi_devices[scsi_bus->bus_device][scsi_bus->target_id]; + + scsi_device_log("SCSI Command 0x%02X for ID %d, status code=%02x\n", scsi_bus->command[0], scsi_bus->target_id, dev->status); + dev->buffer_length = -1; + scsi_device_command_phase0(dev, scsi_bus->command); + scsi_device_log("SCSI ID %i: Command %02X: Buffer Length %i, SCSI Phase %02X\n", scsi_bus->target_id, scsi_bus->command[0], dev->buffer_length, dev->phase); + + scsi_bus->period = 1.0; + scsi_bus->wait_data = 4; + scsi_bus->data_wait = 0; + scsi_bus->command_issued = 1; + + if (dev->status == SCSI_STATUS_OK) { + /*If the SCSI phase is Data In or Data Out, allocate the SCSI buffer based on the transfer length of the command*/ + if (dev->buffer_length && ((dev->phase == SCSI_PHASE_DATA_IN) || (dev->phase == SCSI_PHASE_DATA_OUT))) { + p = scsi_device_get_callback(dev); + scsi_bus->period = (p > 0.0) ? ((p / scsi_bus->divider) * scsi_bus->multi) : (((double) dev->buffer_length) * scsi_bus->speed); + scsi_device_log("SCSI ID %i: command 0x%02x for p = %lf, update = %lf, len = %i, dmamode = %x\n", scsi_bus->target_id, scsi_bus->command[0], scsi_device_get_callback(dev), scsi_bus->period, dev->buffer_length, scsi_bus->tx_mode); + } + } + scsi_bus->bus_phase = dev->phase; + } + } + break; + case STATE_DATAIN: + dev = &scsi_devices[scsi_bus->bus_device][scsi_bus->target_id]; + if ((bus & BUS_ACK) && !(scsi_bus->bus_in & BUS_ACK)) { + if (scsi_bus->data_pos >= dev->buffer_length) { + scsi_bus->bus_out &= ~BUS_REQ; + scsi_device_command_phase1(dev); + scsi_bus->bus_phase = SCSI_PHASE_STATUS; + scsi_bus->wait_data = 4; + scsi_bus->wait_complete = 8; + } else { + if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL)) + scsi_bus->data = dev->sc->temp_buffer[scsi_bus->data_pos++]; + + scsi_device_log("TXMode DataIn=%x, cmd=%02x.\n", scsi_bus->tx_mode, scsi_bus->command[0]); + scsi_bus->bus_out = (scsi_bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(scsi_bus->data) | BUS_DBP | BUS_REQ; + if (scsi_bus->tx_mode == PIO_TX_BUS) { /*If a data in command that is not read 6/10 has been issued*/ + scsi_device_log("DMA mode idle IN=%d.\n", scsi_bus->data_pos); + scsi_bus->data_wait |= 1; + scsi_bus->timer(scsi_bus->priv, scsi_bus->period); + } else { + scsi_device_log("DMA mode IN=%d.\n", scsi_bus->data_pos); + scsi_bus->clear_req = 3; + } + scsi_bus->bus_out &= ~BUS_REQ; + scsi_bus->bus_phase = SCSI_PHASE_DATA_IN; + } + } + break; + case STATE_DATAOUT: + dev = &scsi_devices[scsi_bus->bus_device][scsi_bus->target_id]; + if ((bus & BUS_ACK) && !(scsi_bus->bus_in & BUS_ACK)) { + if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL)) + dev->sc->temp_buffer[scsi_bus->data_pos++] = BUS_GETDATA(bus); + + if (scsi_bus->data_pos >= dev->buffer_length) { + scsi_bus->bus_out &= ~BUS_REQ; + scsi_device_command_phase1(dev); + scsi_bus->bus_phase = SCSI_PHASE_STATUS; + scsi_bus->wait_data = 4; + scsi_bus->wait_complete = 8; + } else { + /*More data is to be transferred, place a request*/ + if (scsi_bus->tx_mode == PIO_TX_BUS) { /*If a data in command that is not write 6/10 has been issued*/ + scsi_device_log("DMA mode idle OUT=%d.\n", scsi_bus->data_pos); + scsi_bus->data_wait |= 1; + scsi_bus->timer(scsi_bus->priv, scsi_bus->period); + scsi_bus->bus_out &= ~BUS_REQ; + } else { + scsi_device_log("DMA mode OUT=%d.\n", scsi_bus->data_pos); + scsi_bus->bus_out |= BUS_REQ; + } + } + } + break; + case STATE_STATUS: + if ((bus & BUS_ACK) && !(scsi_bus->bus_in & BUS_ACK)) { + /*All transfers done, wait until next transfer*/ + scsi_device_identify(&scsi_devices[scsi_bus->bus_device][scsi_bus->target_id], SCSI_LUN_USE_CDB); + scsi_bus->bus_out &= ~BUS_REQ; + scsi_bus->bus_phase = SCSI_PHASE_MESSAGE_IN; + scsi_bus->wait_data = 4; + scsi_bus->wait_complete = 8; + scsi_bus->command_issued = 0; + } + break; + case STATE_MESSAGEIN: + if ((bus & BUS_ACK) && !(scsi_bus->bus_in & BUS_ACK)) { + scsi_bus->bus_out &= ~BUS_REQ; + scsi_bus->bus_phase = BUS_IDLE; + scsi_bus->wait_data = 4; + } + break; + case STATE_MESSAGEOUT: + if ((bus & BUS_ACK) && !(scsi_bus->bus_in & BUS_ACK)) { + scsi_bus->msgout[scsi_bus->msgout_pos++] = BUS_GETDATA(bus); + msglen = scsi_device_get_msg(scsi_bus->msgout, scsi_bus->msgout_pos); + if (scsi_bus->msgout_pos >= msglen) { + if ((scsi_bus->msgout[0] & (0x80 | 0x20)) == 0x80) + scsi_bus->msglun = scsi_bus->msgout[0] & 7; + + scsi_bus->bus_out &= ~BUS_REQ; + scsi_bus->state = STATE_MESSAGE_ID; + } + } + break; + case STATE_MESSAGE_ID: + if ((scsi_bus->target_id != (uint8_t) -1) && scsi_device_present(&scsi_devices[scsi_bus->bus_device][scsi_bus->target_id])) { + scsi_device_log("Device found at ID %i on MSGOUT, Current Bus BSY=%02x\n", scsi_bus->target_id, scsi_bus->bus_out); + scsi_device_identify(&scsi_devices[scsi_bus->bus_device][scsi_bus->target_id], scsi_bus->msglun); + scsi_bus->state = STATE_COMMAND; + scsi_bus->bus_out = BUS_BSY | BUS_REQ; + scsi_bus->command_pos = 0; + SET_BUS_STATE(scsi_bus, SCSI_PHASE_COMMAND); + } + break; + + default: + break; + } + + scsi_bus->bus_in = bus; +} + diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c index e5dff88f8..60f60473e 100644 --- a/src/scsi/scsi_ncr5380.c +++ b/src/scsi/scsi_ncr5380.c @@ -42,8 +42,6 @@ #include <86box/scsi_device.h> #include <86box/scsi_ncr5380.h> -int ncr5380_cmd_len[8] = { 6, 10, 10, 6, 16, 12, 10, 6 }; - #ifdef ENABLE_NCR5380_LOG int ncr5380_do_log = ENABLE_NCR5380_LOG; @@ -62,8 +60,6 @@ ncr5380_log(const char *fmt, ...) # define ncr5380_log(fmt, ...) #endif -#define SET_BUS_STATE(ncr, state) ncr->cur_bus = (ncr->cur_bus & ~(SCSI_PHASE_MESSAGE_IN)) | (state & (SCSI_PHASE_MESSAGE_IN)) - void ncr5380_irq(ncr_t *ncr, int set_irq) { @@ -86,45 +82,15 @@ ncr5380_set_irq(ncr_t *ncr, int irq) ncr->irq = irq; } -static int -ncr5380_get_dev_id(uint8_t data) -{ - for (uint8_t c = 0; c < SCSI_ID_MAX; c++) { - if (data & (1 << c)) - return c; - } - - return -1; -} - -static int -ncr5380_getmsglen(uint8_t *msgp, int len) -{ - uint8_t msg = msgp[0]; - if (msg == 0 || (msg >= 0x02 && msg <= 0x1f) || msg >= 0x80) - return 1; - if (msg >= 0x20 && msg <= 0x2f) - return 2; - if (len < 2) - return 3; - return msgp[1]; -} - static void ncr5380_reset(ncr_t *ncr) { - ncr->command_pos = 0; - ncr->data_pos = 0; - ncr->state = STATE_IDLE; - ncr->clear_req = 0; - ncr->cur_bus = 0; - ncr->tx_data = 0; + scsi_bus_t *scsi_bus = &ncr->scsibus; + ncr->output_data = 0; - ncr->data_wait = 0; ncr->mode = 0; ncr->tcr = 0; ncr->icr = 0; - ncr->dma_mode = DMA_IDLE; ncr5380_log("NCR Reset\n"); ncr->timer(ncr->priv, 0.0); @@ -132,6 +98,17 @@ ncr5380_reset(ncr_t *ncr) for (int i = 0; i < 8; i++) scsi_device_reset(&scsi_devices[ncr->bus][i]); + scsi_bus->state = STATE_IDLE; + scsi_bus->clear_req = 0; + scsi_bus->wait_complete = 0; + scsi_bus->wait_data = 0; + scsi_bus->bus_in = 0; + scsi_bus->bus_out = 0; + scsi_bus->command_pos = 0; + scsi_bus->data_wait = 0; + scsi_bus->data = 0; + scsi_bus->command_issued = 0; + ncr5380_irq(ncr, 0); } @@ -173,280 +150,10 @@ ncr5380_get_bus_host(ncr_t *ncr) return (bus_host | BUS_SETDATA(ncr->output_data)); } -void -ncr5380_bus_read(ncr_t *ncr) -{ - const scsi_device_t *dev; - int phase; - - /*Wait processes to handle bus requests*/ - if (ncr->clear_req) { - ncr->clear_req--; - if (!ncr->clear_req) { - ncr5380_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) { - dev = &scsi_devices[ncr->bus][ncr->target_id]; - SET_BUS_STATE(ncr, ncr->new_phase); - phase = (ncr->cur_bus & SCSI_PHASE_MESSAGE_IN); - - if (phase == SCSI_PHASE_DATA_IN) { - if ((ncr->dma_mode == DMA_IDLE) || ncr->dma_initiator_receive_ext || (ncr->wait_data_back == 1)) { - ncr5380_log("Phase Data In.\n"); - if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL)) - ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++]; - - ncr->state = STATE_DATAIN; - ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP; - } - } else if (phase == SCSI_PHASE_DATA_OUT) { - if (ncr->new_phase & BUS_IDLE) { - ncr->state = STATE_IDLE; - ncr->cur_bus &= ~BUS_BSY; - } else { - if ((ncr->dma_mode == DMA_IDLE) || ncr->dma_send_ext || (ncr->wait_data_back == 1)) - ncr->state = STATE_DATAOUT; - } - } else if (phase == SCSI_PHASE_STATUS) { - ncr5380_log("Phase Status.\n"); - ncr->wait_data_back = 0; - 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 (phase == SCSI_PHASE_MESSAGE_IN) { - ncr5380_log("Phase Message In.\n"); - ncr->state = STATE_MESSAGEIN; - ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(0) | BUS_DBP; - } else if (phase == SCSI_PHASE_MESSAGE_OUT) { - ncr->cur_bus |= BUS_REQ; - ncr->state = STATE_MESSAGEOUT; - ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->target_id >> 5) | BUS_DBP; - } - } - } - - if (ncr->wait_complete) { - ncr->wait_complete--; - if (!ncr->wait_complete) - ncr->cur_bus |= BUS_REQ; - } -} - -void -ncr5380_bus_update(ncr_t *ncr, int bus) -{ - scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; - double p; - uint8_t sel_data; - int msglen; - - /*Start the SCSI command layer, which will also make the timings*/ - if (bus & BUS_ARB) - ncr->state = STATE_IDLE; - - ncr5380_log("State = %i\n", ncr->state); - - switch (ncr->state) { - case STATE_IDLE: - ncr->clear_req = ncr->wait_data = ncr->wait_complete = 0; - if ((bus & BUS_SEL) && !(bus & BUS_BSY)) { - ncr5380_log("Selection phase\n"); - sel_data = BUS_GETDATA(bus); - - ncr->target_id = ncr5380_get_dev_id(sel_data); - - ncr5380_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 != (uint8_t) -1) && scsi_device_present(&scsi_devices[ncr->bus][ncr->target_id])) { - ncr->cur_bus |= BUS_BSY; - ncr->state = STATE_SELECT; - } else { - ncr5380_log("Device not found at ID %i, Current Bus BSY=%02x\n", ncr->target_id, ncr->cur_bus); - ncr->cur_bus = 0; - } - } - break; - case STATE_SELECT: - if (!(bus & BUS_SEL)) { - if (!(bus & BUS_ATN)) { - if ((ncr->target_id != (uint8_t) -1) && scsi_device_present(&scsi_devices[ncr->bus][ncr->target_id])) { - ncr5380_log("Device found at ID %i, Current Bus BSY=%02x\n", ncr->target_id, ncr->cur_bus); - ncr->state = STATE_COMMAND; - ncr->cur_bus = BUS_BSY | BUS_REQ; - ncr5380_log("CurBus BSY|REQ=%02x\n", ncr->cur_bus); - ncr->command_pos = 0; - SET_BUS_STATE(ncr, SCSI_PHASE_COMMAND); - } else { - ncr->state = STATE_IDLE; - ncr->cur_bus = 0; - } - } else { - ncr5380_log("Set to SCSI Message Out\n"); - ncr->new_phase = SCSI_PHASE_MESSAGE_OUT; - ncr->wait_data = 4; - ncr->msgout_pos = 0; - ncr->is_msgout = 1; - } - } - break; - case STATE_COMMAND: - if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - /*Write command byte to the output data register*/ - ncr->command[ncr->command_pos++] = BUS_GETDATA(bus); - ncr->clear_req = 3; - ncr->new_phase = ncr->cur_bus & SCSI_PHASE_MESSAGE_IN; - ncr->cur_bus &= ~BUS_REQ; - - ncr5380_log("Command pos=%i, output data=%02x\n", ncr->command_pos, BUS_GETDATA(bus)); - - if (ncr->command_pos == ncr5380_cmd_len[(ncr->command[0] >> 5) & 7]) { - if (ncr->is_msgout) { - ncr->is_msgout = 0; -#if 0 - ncr->command[1] = (ncr->command[1] & 0x1f) | (ncr->msglun << 5); -#endif - } - - /*Reset data position to default*/ - ncr->data_pos = 0; - - dev = &scsi_devices[ncr->bus][ncr->target_id]; - - ncr5380_log("SCSI Command 0x%02X for ID %d, status code=%02x\n", ncr->command[0], ncr->target_id, dev->status); - dev->buffer_length = -1; - scsi_device_command_phase0(dev, ncr->command); - ncr5380_log("SCSI ID %i: Command %02X: Buffer Length %i, SCSI Phase %02X\n", ncr->target_id, ncr->command[0], dev->buffer_length, dev->phase); - - ncr->period = 1.0; - ncr->wait_data = 4; - ncr->data_wait = 0; - - if (dev->status == SCSI_STATUS_OK) { - /*If the SCSI phase is Data In or Data Out, allocate the SCSI buffer based on the transfer length of the command*/ - if (dev->buffer_length && ((dev->phase == SCSI_PHASE_DATA_IN) || (dev->phase == SCSI_PHASE_DATA_OUT))) { - p = scsi_device_get_callback(dev); - ncr->period = (p > 0.0) ? p : (((double) dev->buffer_length) * 0.2); - ncr5380_log("SCSI ID %i: command 0x%02x for p = %lf, update = %lf, len = %i, dmamode = %x\n", ncr->target_id, ncr->command[0], scsi_device_get_callback(dev), ncr->period, dev->buffer_length, ncr->dma_mode); - } - } - ncr->new_phase = dev->phase; - } - } - break; - case STATE_DATAIN: - dev = &scsi_devices[ncr->bus][ncr->target_id]; - if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - if (ncr->data_pos >= dev->buffer_length) { - ncr->cur_bus &= ~BUS_REQ; - ncr5380_log("CMD Phase1 DataIn.\n"); - scsi_device_command_phase1(dev); - ncr->new_phase = SCSI_PHASE_STATUS; - ncr->wait_data = 4; - ncr->wait_complete = 8; - } else { - if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL)) - ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++]; - - ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ; - if (ncr->dma_mode == DMA_IDLE) { /*If a data in command that is not read 6/10 has been issued*/ - ncr->data_wait |= 1; - ncr5380_log("DMA mode idle IN=%d.\n", ncr->data_pos); - ncr->timer(ncr->priv, ncr->period); - } else { - ncr5380_log("DMA mode IN=%d.\n", ncr->data_pos); - ncr->clear_req = 3; - } - - ncr->cur_bus &= ~BUS_REQ; - ncr->new_phase = SCSI_PHASE_DATA_IN; - } - } - break; - case STATE_DATAOUT: - dev = &scsi_devices[ncr->bus][ncr->target_id]; - if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL)) - dev->sc->temp_buffer[ncr->data_pos++] = BUS_GETDATA(bus); - - if (ncr->data_pos >= dev->buffer_length) { - ncr->cur_bus &= ~BUS_REQ; - scsi_device_command_phase1(dev); - ncr->new_phase = SCSI_PHASE_STATUS; - ncr->wait_data = 4; - ncr->wait_complete = 8; - } else { - /*More data is to be transferred, place a request*/ - if (ncr->dma_mode == DMA_IDLE) { /*If a data out command that is not write 6/10 has been issued*/ - ncr->data_wait |= 1; - ncr5380_log("DMA mode idle out\n"); - ncr->timer(ncr->priv, ncr->period); - } else - ncr->clear_req = 3; - - ncr->cur_bus &= ~BUS_REQ; - ncr5380_log("CurBus ~REQ_DataOut=%02x\n", ncr->cur_bus); - } - } - break; - case STATE_STATUS: - if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - /*All transfers done, wait until next transfer*/ - scsi_device_identify(&scsi_devices[ncr->bus][ncr->target_id], SCSI_LUN_USE_CDB); - ncr->cur_bus &= ~BUS_REQ; - ncr->new_phase = SCSI_PHASE_MESSAGE_IN; - ncr->wait_data = 4; - ncr->wait_complete = 8; - } - break; - case STATE_MESSAGEIN: - if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - ncr->cur_bus &= ~BUS_REQ; - ncr->new_phase = BUS_IDLE; - ncr->wait_data = 4; - } - break; - case STATE_MESSAGEOUT: - ncr5380_log("Ack on MSGOUT = %02x\n", (bus & BUS_ACK)); - if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - ncr->msgout[ncr->msgout_pos++] = BUS_GETDATA(bus); - msglen = ncr5380_getmsglen(ncr->msgout, ncr->msgout_pos); - if (ncr->msgout_pos >= msglen) { - if ((ncr->msgout[0] & (0x80 | 0x20)) == 0x80) - ncr->msglun = ncr->msgout[0] & 7; - ncr->cur_bus &= ~BUS_REQ; - ncr->state = STATE_MESSAGE_ID; - } - } - break; - case STATE_MESSAGE_ID: - if ((ncr->target_id != (uint8_t) -1) && scsi_device_present(&scsi_devices[ncr->bus][ncr->target_id])) { - ncr5380_log("Device found at ID %i on MSGOUT, Current Bus BSY=%02x\n", ncr->target_id, ncr->cur_bus); - scsi_device_identify(&scsi_devices[ncr->bus][ncr->target_id], ncr->msglun); - ncr->state = STATE_COMMAND; - ncr->cur_bus = BUS_BSY | BUS_REQ; - ncr5380_log("CurBus BSY|REQ=%02x\n", ncr->cur_bus); - ncr->command_pos = 0; - SET_BUS_STATE(ncr, SCSI_PHASE_COMMAND); - } - break; - - default: - break; - } - - ncr->bus_in = bus; -} - void ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr) { + scsi_bus_t *scsi_bus = &ncr->scsibus; int bus_host = 0; ncr5380_log("NCR5380 write(%04x,%02x)\n", port & 7, val); @@ -462,8 +169,10 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr) if ((val & 0x80) && !(ncr->icr & 0x80)) { ncr5380_log("Resetting the 5380\n"); ncr5380_reset(ncr); + ncr5380_irq(ncr, 1); } ncr->icr = val; + ncr5380_log("ICR WaitData=%d, ClearReq=%d.\n", scsi_bus->wait_data, scsi_bus->clear_req); break; case 2: /* Mode register */ @@ -472,10 +181,8 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr) ncr->icr &= ~ICR_ARB_LOST; ncr->icr |= ICR_ARB_IN_PROGRESS; } - ncr->mode = val; - - ncr->dma_mode_ext(ncr, ncr->priv); + ncr->dma_mode_ext(ncr, ncr->priv, val); break; case 3: /* Target Command Register */ @@ -488,17 +195,17 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr) break; case 5: /* start DMA Send */ - ncr5380_log("Write: start DMA send register\n"); + pclog("Write: start DMA send register\n"); /*a Write 6/10 has occurred, start the timer when the block count is loaded*/ - ncr->dma_mode = DMA_SEND; + scsi_bus->tx_mode = DMA_OUT_TX_BUS; if (ncr->dma_send_ext) ncr->dma_send_ext(ncr, ncr->priv); break; case 7: /* start DMA Initiator Receive */ - ncr5380_log("[%04X:%08X]: Write: start DMA initiator receive register, dma? = %02x\n", CS, cpu_state.pc, ncr->mode & MODE_DMA); + ncr5380_log("[%04X:%08X]: Write: start DMA initiator receive register, waitdata=%d, clearreq=%d.\n", CS, cpu_state.pc, scsi_bus->wait_data, scsi_bus->clear_req); /*a Read 6/10 has occurred, start the timer when the block count is loaded*/ - ncr->dma_mode = DMA_INITIATOR_RECEIVE; + scsi_bus->tx_mode = DMA_IN_TX_BUS; if (ncr->dma_initiator_receive_ext) ncr->dma_initiator_receive_ext(ncr, ncr->priv); break; @@ -509,12 +216,13 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr) } bus_host = ncr5380_get_bus_host(ncr); - ncr5380_bus_update(ncr, bus_host); + scsi_bus_update(scsi_bus, bus_host); } uint8_t ncr5380_read(uint16_t port, ncr_t *ncr) { + scsi_bus_t *scsi_bus = &ncr->scsibus; uint8_t ret = 0xff; int bus; int bus_state; @@ -524,12 +232,17 @@ ncr5380_read(uint16_t port, ncr_t *ncr) ncr5380_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*/ - ret = ncr->output_data; - ncr5380_log("[%04X:%08X]: Data Bus Phase, ret=%02x, clearreq=%d, waitdata=%x.\n", CS, cpu_state.pc, ret, ncr->clear_req, ncr->wait_data); + if (scsi_bus->command_issued) { + bus = scsi_bus_read(scsi_bus); + ret = BUS_GETDATA(bus); + } else + ret = ncr->output_data; + + ncr5380_log("[%04X:%08X]: Data Bus Phase, ret=%02x, clearreq=%d, waitdata=%x, txmode=%x.\n", CS, cpu_state.pc, ret, scsi_bus->clear_req, scsi_bus->wait_data, scsi_bus->tx_mode); } else { /*Return the data from the SCSI bus*/ - ncr5380_bus_read(ncr); - ret = BUS_GETDATA(ncr->cur_bus); + bus = scsi_bus_read(scsi_bus); + ret = BUS_GETDATA(bus); ncr5380_log("[%04X:%08X]: NCR Get SCSI bus data=%02x.\n", CS, cpu_state.pc, ret); } break; @@ -552,15 +265,16 @@ ncr5380_read(uint16_t port, ncr_t *ncr) case 4: /* Current SCSI Bus status */ ncr5380_log("Read: SCSI bus status register\n"); ret = 0; - ncr5380_bus_read(ncr); - ncr5380_log("NCR cur bus stat=%02x\n", ncr->cur_bus & 0xff); - ret |= (ncr->cur_bus & 0xff); + bus = scsi_bus_read(scsi_bus); + ret |= (bus & 0xff); if (ncr->icr & ICR_SEL) ret |= BUS_SEL; if (ncr->icr & ICR_BSY) ret |= BUS_BSY; - // if ((ret & SCSI_PHASE_MESSAGE_IN) == SCSI_PHASE_MESSAGE_IN) - // ret &= ~BUS_REQ; + + /*Note by TC1995: Horrible hack, I know.*/ + (void) scsi_bus_read(scsi_bus); + (void) scsi_bus_read(scsi_bus); break; case 5: /* Bus and Status register */ @@ -571,13 +285,12 @@ ncr5380_read(uint16_t port, ncr_t *ncr) ncr5380_log("Get host from Interrupt\n"); /*Check if the phase in process matches with TCR's*/ - if ((bus & SCSI_PHASE_MESSAGE_IN) == (ncr->cur_bus & SCSI_PHASE_MESSAGE_IN)) { + if ((bus & SCSI_PHASE_MESSAGE_IN) == (scsi_bus->bus_out & SCSI_PHASE_MESSAGE_IN)) { ncr5380_log("Phase match\n"); ret |= STATUS_PHASE_MATCH; } - ncr5380_bus_read(ncr); - bus = ncr->cur_bus; + bus = scsi_bus_read(scsi_bus); if ((bus & BUS_ACK) || (ncr->icr & ICR_ACK)) ret |= STATUS_ACK; @@ -610,8 +323,8 @@ ncr5380_read(uint16_t port, ncr_t *ncr) case 6: ncr5380_log("Read: Input Data.\n"); - ncr5380_bus_read(ncr); - ret = BUS_GETDATA(ncr->cur_bus); + bus = scsi_bus_read(scsi_bus); + ret = BUS_GETDATA(bus); break; case 7: /* reset Parity/Interrupt */ diff --git a/src/scsi/scsi_ncr53c400.c b/src/scsi/scsi_ncr53c400.c index e028c7b42..a9d07af95 100644 --- a/src/scsi/scsi_ncr53c400.c +++ b/src/scsi/scsi_ncr53c400.c @@ -121,7 +121,8 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv) { ncr53c400_t *ncr400 = (ncr53c400_t *) priv; ncr_t *ncr = &ncr400->ncr; - scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; + scsi_bus_t *scsi_bus = &ncr->scsibus; + scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id]; addr &= 0x3fff; @@ -146,16 +147,9 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv) if (ncr400->buffer_host_pos == MIN(128, dev->buffer_length)) { ncr400->status_ctrl |= STATUS_BUFFER_NOT_READY; ncr400->busy = 1; - if (!(ncr->mode & MODE_MONITOR_BUSY) && ((scsi_device_get_callback(dev) > 0.0))) - timer_on_auto(&ncr400->timer, ncr->period / 250.0); - else if ((ncr->mode & MODE_MONITOR_BUSY) && !ncr->wait_data) { - if (scsi_device_get_callback(dev) > 0.0) - timer_on_auto(&ncr400->timer, 100.0); - else - timer_on_auto(&ncr400->timer, 40.0); - } } - } + } else + ncr53c400_log("No Write.\n"); break; case 0x3980: @@ -173,7 +167,7 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv) break; case 0x3981: /* block counter register */ - ncr53c400_log("Write block counter register: val=%d, dma mode=%x, period=%lf.\n", val, ncr->dma_mode, ncr->period); + ncr53c400_log("Write block counter register: val=%d, dma mode=%x, period=%lf.\n", val, scsi_bus->tx_mode, scsi_bus->period); ncr400->block_count = val; ncr400->block_count_loaded = 1; @@ -186,17 +180,11 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv) } if ((ncr->mode & MODE_DMA) && (dev->buffer_length > 0)) { memset(ncr400->buffer, 0, MIN(128, dev->buffer_length)); - if (ncr->mode & MODE_MONITOR_BUSY) - timer_on_auto(&ncr400->timer, (ncr->period / 4.0) * 3.0); - else if (scsi_device_get_callback(dev) > 0.0) - timer_on_auto(&ncr400->timer, 40.0); - else - timer_on_auto(&ncr400->timer, ncr->period); - - ncr->wait_data_back = ncr->wait_data; - ncr53c400_log("DMA timer on=%02x, callback=%lf, scsi buflen=%d, waitdata=%d, waitcomplete=%d, clearreq=%d, datawait=%d, enabled=%d.\n", - ncr->mode & MODE_MONITOR_BUSY, scsi_device_get_callback(dev), dev->buffer_length, ncr->wait_data, ncr->wait_complete, ncr->clear_req, ncr->data_wait, timer_is_enabled(&ncr400->timer)); - } + timer_on_auto(&ncr400->timer, scsi_bus->period); + ncr53c400_log("DMA timer on=%02x, callback=%lf, scsi buflen=%d, waitdata=%d, waitcomplete=%d, clearreq=%d, p=%lf enabled=%d.\n", + ncr->mode & MODE_MONITOR_BUSY, scsi_device_get_callback(dev), dev->buffer_length, scsi_bus->wait_data, scsi_bus->wait_complete, scsi_bus->clear_req, scsi_bus->period, timer_is_enabled(&ncr400->timer)); + } else + ncr53c400_log("No Timer.\n"); break; default: @@ -216,7 +204,8 @@ ncr53c400_read(uint32_t addr, void *priv) { ncr53c400_t *ncr400 = (ncr53c400_t *) priv; ncr_t *ncr = &ncr400->ncr; - scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; + scsi_bus_t *scsi_bus = &ncr->scsibus; + scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id]; uint8_t ret = 0xff; addr &= 0x3fff; @@ -240,7 +229,7 @@ ncr53c400_read(uint32_t addr, void *priv) break; case 0x3900: - if (ncr400->buffer_host_pos >= MIN(128, dev->buffer_length) || (!(ncr400->status_ctrl & CTRL_DATA_DIR))) { + if ((ncr400->buffer_host_pos >= MIN(128, dev->buffer_length)) || (!(ncr400->status_ctrl & CTRL_DATA_DIR))) { ret = 0xff; ncr53c400_log("No Read.\n"); } else { @@ -249,15 +238,6 @@ ncr53c400_read(uint32_t addr, void *priv) if (ncr400->buffer_host_pos == MIN(128, dev->buffer_length)) { ncr400->status_ctrl |= STATUS_BUFFER_NOT_READY; - ncr53c400_log("Transfer busy read, status = %02x.\n", ncr400->status_ctrl); - if (!(ncr->mode & MODE_MONITOR_BUSY) && (scsi_device_get_callback(dev) > 0.0)) - timer_on_auto(&ncr400->timer, ncr->period / 250.0); - else if ((ncr->mode & MODE_MONITOR_BUSY) && !ncr->wait_data) { - if (scsi_device_get_callback(dev) > 0.0) - timer_on_auto(&ncr400->timer, 100.0); - else - timer_on_auto(&ncr400->timer, 40.0); - } } } break; @@ -272,7 +252,7 @@ ncr53c400_read(uint32_t addr, void *priv) if (ncr->mode & 0x30) { /*Parity bits*/ if (!(ncr->mode & MODE_DMA)) { /*This is to avoid RTBios 8.10R BIOS problems with the hard disk and detection.*/ ret |= 0x01; /*If the parity bits are set, bit 0 of the 53c400 status port should be set as well.*/ - ncr->mode = 0; /*Required by RTASPI10.SYS otherwise it won't initialize.*/ + ncr->mode = 0x00; /*Required by RTASPI10.SYS otherwise it won't initialize.*/ } } ncr53c400_log("NCR 53c400 status=%02x.\n", ret); @@ -411,46 +391,47 @@ t130b_in(uint16_t port, void *priv) } static void -ncr53c400_dma_mode_ext(void *priv, void *ext_priv) +ncr53c400_dma_mode_ext(void *priv, UNUSED(void *ext_priv), uint8_t val) { - ncr53c400_t *ncr400 = (ncr53c400_t *) ext_priv; ncr_t *ncr = (ncr_t *) priv; + scsi_bus_t *scsi_bus = &ncr->scsibus; /*When a pseudo-DMA transfer has completed (Send or Initiator Receive), mark it as complete and idle the status*/ - ncr53c400_log("BlockCountLoaded=%d.\n", ncr400->block_count_loaded); - if (!ncr400->block_count_loaded) { - if (!(ncr->mode & MODE_DMA)) { - ncr53c400_log("No DMA mode\n"); - ncr->tcr &= ~TCR_LAST_BYTE_SENT; - ncr->isr &= ~STATUS_END_OF_DMA; - ncr->dma_mode = DMA_IDLE; - } + ncr53c400_log("NCR 53c400: BlockCountLoaded=%d, DMA mode enabled=%02x, valDMA=%02x.\n", ncr400->block_count_loaded, ncr->mode & MODE_DMA, val & MODE_DMA); + if (!(val & MODE_DMA) && (ncr->mode & MODE_DMA)) { + ncr->tcr &= ~TCR_LAST_BYTE_SENT; + ncr->isr &= ~STATUS_END_OF_DMA; + scsi_bus->tx_mode = PIO_TX_BUS; } } static void ncr53c400_callback(void *priv) { - ncr53c400_t *ncr400 = (void *) priv; + ncr53c400_t *ncr400 = (ncr53c400_t *) priv; ncr_t *ncr = &ncr400->ncr; - scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; + scsi_bus_t *scsi_bus = &ncr->scsibus; + scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id]; int bus; uint8_t c; uint8_t temp; + uint8_t status; - if (ncr->dma_mode != DMA_IDLE) + if (scsi_bus->tx_mode != PIO_TX_BUS) timer_on_auto(&ncr400->timer, 1.0); - if (ncr->data_wait & 1) { - ncr->clear_req = 3; - ncr->data_wait &= ~1; + if (scsi_bus->data_wait & 1) { + scsi_bus->clear_req = 3; + scsi_bus->data_wait &= ~1; } - if (ncr->dma_mode == DMA_IDLE) + if (scsi_bus->tx_mode == PIO_TX_BUS) { + ncr53c400_log("Timer CMD=%02x.\n", scsi_bus->command[0]); return; + } - switch (ncr->dma_mode) { - case DMA_SEND: + switch (scsi_bus->tx_mode) { + case DMA_OUT_TX_BUS: if (ncr400->status_ctrl & CTRL_DATA_DIR) { ncr53c400_log("DMA_SEND with DMA direction set wrong\n"); break; @@ -468,8 +449,8 @@ ncr53c400_callback(void *priv) while (1) { for (c = 0; c < 10; c++) { - ncr5380_bus_read(ncr); - if (ncr->cur_bus & BUS_REQ) + status = scsi_bus_read(scsi_bus); + if (status & BUS_REQ) break; } /* Data ready. */ @@ -478,8 +459,8 @@ ncr53c400_callback(void *priv) bus = ncr5380_get_bus_host(ncr) & ~BUS_DATAMASK; bus |= BUS_SETDATA(temp); - ncr5380_bus_update(ncr, bus | BUS_ACK); - ncr5380_bus_update(ncr, bus & ~BUS_ACK); + scsi_bus_update(scsi_bus, bus | BUS_ACK); + scsi_bus_update(scsi_bus, bus & ~BUS_ACK); ncr400->buffer_pos++; ncr53c400_log("NCR 53c400 Buffer pos for writing = %d\n", ncr400->buffer_pos); @@ -492,7 +473,7 @@ ncr53c400_callback(void *priv) ncr400->block_count = (ncr400->block_count - 1) & 0xff; ncr53c400_log("NCR 53c400 Remaining blocks to be written=%d\n", ncr400->block_count); if (!ncr400->block_count) { - ncr->dma_mode = DMA_IDLE; + scsi_bus->tx_mode = PIO_TX_BUS; ncr400->block_count_loaded = 0; ncr53c400_log("IO End of write transfer\n"); ncr->tcr |= TCR_LAST_BYTE_SENT; @@ -507,7 +488,7 @@ ncr53c400_callback(void *priv) } break; - case DMA_INITIATOR_RECEIVE: + case DMA_IN_TX_BUS: if (!(ncr400->status_ctrl & CTRL_DATA_DIR)) { ncr53c400_log("DMA_INITIATOR_RECEIVE with DMA direction set wrong\n"); break; @@ -523,18 +504,18 @@ ncr53c400_callback(void *priv) while (1) { for (c = 0; c < 10; c++) { - ncr5380_bus_read(ncr); - if (ncr->cur_bus & BUS_REQ) + status = scsi_bus_read(scsi_bus); + if (status & BUS_REQ) break; } /* Data ready. */ - ncr5380_bus_read(ncr); - temp = BUS_GETDATA(ncr->cur_bus); + bus = scsi_bus_read(scsi_bus); + temp = BUS_GETDATA(bus); bus = ncr5380_get_bus_host(ncr); - ncr5380_bus_update(ncr, bus | BUS_ACK); - ncr5380_bus_update(ncr, bus & ~BUS_ACK); + scsi_bus_update(scsi_bus, bus | BUS_ACK); + scsi_bus_update(scsi_bus, bus & ~BUS_ACK); ncr400->buffer[ncr400->buffer_pos++] = temp; ncr53c400_log("NCR 53c400 Buffer pos for reading = %d\n", ncr400->buffer_pos); @@ -546,7 +527,7 @@ ncr53c400_callback(void *priv) ncr400->block_count = (ncr400->block_count - 1) & 0xff; ncr53c400_log("NCR 53c400 Remaining blocks to be read=%d\n", ncr400->block_count); if (!ncr400->block_count) { - ncr->dma_mode = DMA_IDLE; + scsi_bus->tx_mode = PIO_TX_BUS; ncr400->block_count_loaded = 0; ncr53c400_log("IO End of read transfer\n"); ncr->isr |= STATUS_END_OF_DMA; @@ -564,13 +545,12 @@ ncr53c400_callback(void *priv) break; } - ncr53c400_log("Bus Read.\n"); - ncr5380_bus_read(ncr); + status = scsi_bus_read(scsi_bus); - if (!(ncr->cur_bus & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) { + if (!(status & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) { ncr53c400_log("Updating DMA\n"); ncr->mode &= ~MODE_DMA; - ncr->dma_mode = DMA_IDLE; + scsi_bus->tx_mode = PIO_TX_BUS; ncr400->block_count_loaded = 0; } } @@ -643,6 +623,7 @@ ncr53c400_init(const device_t *info) const char *fn; ncr53c400_t *ncr400; ncr_t *ncr; + scsi_bus_t *scsi_bus; ncr400 = malloc(sizeof(ncr53c400_t)); memset(ncr400, 0x00, sizeof(ncr53c400_t)); @@ -651,6 +632,7 @@ ncr53c400_init(const device_t *info) ncr400->type = info->local; ncr->bus = scsi_get_bus(); + scsi_bus = &ncr->scsibus; switch (ncr400->type) { case ROM_LCS6821N: /* Longshine LCS6821N */ @@ -734,11 +716,17 @@ ncr53c400_init(const device_t *info) ncr->dma_send_ext = NULL; ncr->dma_initiator_receive_ext = NULL; ncr->timer = ncr53c400_timer_on_auto; + scsi_bus->bus_device = ncr->bus; + scsi_bus->timer = ncr->timer; + scsi_bus->priv = ncr->priv; ncr400->status_ctrl = STATUS_BUFFER_NOT_READY; ncr400->buffer_host_pos = 128; timer_add(&ncr400->timer, ncr53c400_callback, ncr400, 0); scsi_bus_set_speed(ncr->bus, 5000000.0); + scsi_bus->speed = 0.2; + scsi_bus->divider = 2.0; + scsi_bus->multi = 1.750; return ncr400; } diff --git a/src/scsi/scsi_t128.c b/src/scsi/scsi_t128.c index c878bbb91..0d653469a 100644 --- a/src/scsi/scsi_t128.c +++ b/src/scsi/scsi_t128.c @@ -69,7 +69,8 @@ t128_write(uint32_t addr, uint8_t val, void *priv) { t128_t *t128 = (t128_t *) priv; ncr_t *ncr = &t128->ncr; - const scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; + scsi_bus_t *scsi_bus = &ncr->scsibus; + const scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id]; addr &= 0x3fff; if ((addr >= 0x1800) && (addr < 0x1880)) @@ -84,7 +85,7 @@ t128_write(uint32_t addr, uint8_t val, void *priv) ncr5380_write((addr - 0x1d00) >> 5, val, ncr); else if ((addr >= 0x1e00) && (addr < 0x2000)) { if ((t128->host_pos < MIN(512, dev->buffer_length)) && - (ncr->dma_mode == DMA_SEND)) { + (scsi_bus->tx_mode == DMA_OUT_TX_BUS)) { t128->buffer[t128->host_pos] = val; t128->host_pos++; @@ -106,7 +107,8 @@ t128_read(uint32_t addr, void *priv) { t128_t *t128 = (t128_t *) priv; ncr_t *ncr = &t128->ncr; - scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; + scsi_bus_t *scsi_bus = &ncr->scsibus; + scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id]; uint8_t ret = 0xff; addr &= 0x3fff; @@ -124,7 +126,7 @@ t128_read(uint32_t addr, void *priv) ret = ncr5380_read((addr - 0x1d00) >> 5, ncr); else if (addr >= 0x1e00 && addr < 0x2000) { if ((t128->host_pos >= MIN(512, dev->buffer_length)) || - (ncr->dma_mode != DMA_INITIATOR_RECEIVE)) + (scsi_bus->tx_mode != DMA_IN_TX_BUS)) ret = 0xff; else { ret = t128->buffer[t128->host_pos++]; @@ -135,8 +137,8 @@ t128_read(uint32_t addr, void *priv) if (t128->host_pos == MIN(512, dev->buffer_length)) { t128->status &= ~0x04; t128_log("T128 Transfer busy read, status = %02x, period = %lf\n", - t128->status, ncr->period); - if ((ncr->period == 0.2) || (ncr->period == 0.02)) + t128->status, scsi_bus->period); + if ((scsi_bus->period == 0.2) || (scsi_bus->period == 0.02)) timer_on_auto(&t128->timer, 40.2); } else if ((t128->host_pos < MIN(512, dev->buffer_length)) && (scsi_device_get_callback(dev) > 100.0)) @@ -148,15 +150,16 @@ t128_read(uint32_t addr, void *priv) } static void -t128_dma_mode_ext(void *priv, void *ext_priv) +t128_dma_mode_ext(void *priv, void *ext_priv, UNUSED(uint8_t val)) { t128_t *t128 = (t128_t *) ext_priv; ncr_t *ncr = (ncr_t *) priv; + scsi_bus_t *scsi_bus = &ncr->scsibus; /*Don't stop the timer until it finishes the transfer*/ if (t128->block_loaded && (ncr->mode & MODE_DMA)) { t128_log("Continuing DMA mode\n"); - timer_on_auto(&t128->timer, ncr->period + 1.0); + timer_on_auto(&t128->timer, scsi_bus->period + 1.0); } /*When a pseudo-DMA transfer has completed (Send or Initiator Receive), mark it as complete and idle the status*/ @@ -164,7 +167,7 @@ t128_dma_mode_ext(void *priv, void *ext_priv) t128_log("No DMA mode\n"); ncr->tcr &= ~TCR_LAST_BYTE_SENT; ncr->isr &= ~STATUS_END_OF_DMA; - ncr->dma_mode = DMA_IDLE; + scsi_bus->tx_mode = PIO_TX_BUS; } } @@ -173,7 +176,8 @@ t128_dma_send_ext(void *priv, void *ext_priv) { t128_t *t128 = (t128_t *) ext_priv; ncr_t *ncr = (ncr_t *) priv; - scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; + scsi_bus_t *scsi_bus = &ncr->scsibus; + scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id]; if ((ncr->mode & MODE_DMA) && !timer_is_on(&t128->timer) && (dev->buffer_length > 0)) { memset(t128->buffer, 0, MIN(512, dev->buffer_length)); @@ -194,7 +198,8 @@ t128_dma_initiator_receive_ext(void *priv, void *ext_priv) { t128_t *t128 = (t128_t *) ext_priv; ncr_t *ncr = (ncr_t *) priv; - scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; + scsi_bus_t *scsi_bus = &ncr->scsibus; + scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id]; if ((ncr->mode & MODE_DMA) && !timer_is_on(&t128->timer) && (dev->buffer_length > 0)) { memset(t128->buffer, 0, MIN(512, dev->buffer_length)); @@ -227,27 +232,29 @@ t128_callback(void *priv) { t128_t *t128 = (void *) priv; ncr_t *ncr = &t128->ncr; - scsi_device_t *dev = &scsi_devices[ncr->bus][ncr->target_id]; - int bus; - uint8_t c; - uint8_t temp; + scsi_bus_t *scsi_bus = &ncr->scsibus; + scsi_device_t *dev = &scsi_devices[ncr->bus][scsi_bus->target_id]; + int bus; + uint8_t c; + uint8_t temp; + uint8_t status; - if ((ncr->dma_mode != DMA_IDLE) && (ncr->mode & MODE_DMA) && t128->block_loaded) { + if ((scsi_bus->tx_mode != PIO_TX_BUS) && (ncr->mode & MODE_DMA) && t128->block_loaded) { if ((t128->host_pos == MIN(512, dev->buffer_length)) && t128->block_count) t128->status |= 0x04; - timer_on_auto(&t128->timer, ncr->period / 55.0); + timer_on_auto(&t128->timer, scsi_bus->period / 55.0); } - if (ncr->data_wait & 1) { - ncr->clear_req = 3; - ncr->data_wait &= ~1; - if (ncr->dma_mode == DMA_IDLE) + if (scsi_bus->data_wait & 1) { + scsi_bus->clear_req = 3; + scsi_bus->data_wait &= ~1; + if (scsi_bus->tx_mode == PIO_TX_BUS) return; } - switch (ncr->dma_mode) { - case DMA_SEND: + switch (scsi_bus->tx_mode) { + case DMA_OUT_TX_BUS: if (!(t128->status & 0x04)) { t128_log("Write status busy, block count = %i, host pos = %i\n", t128->block_count, t128->host_pos); break; @@ -263,8 +270,8 @@ t128_callback(void *priv) write_again: for (c = 0; c < 10; c++) { - ncr5380_bus_read(ncr); - if (ncr->cur_bus & BUS_REQ) + status = scsi_bus_read(scsi_bus); + if (status & BUS_REQ) break; } @@ -274,8 +281,8 @@ write_again: bus = ncr5380_get_bus_host(ncr) & ~BUS_DATAMASK; bus |= BUS_SETDATA(temp); - ncr5380_bus_update(ncr, bus | BUS_ACK); - ncr5380_bus_update(ncr, bus & ~BUS_ACK); + scsi_bus_update(scsi_bus, bus | BUS_ACK); + scsi_bus_update(scsi_bus, bus & ~BUS_ACK); t128->pos++; t128_log("T128 Buffer pos for writing = %d\n", t128->pos); @@ -302,7 +309,7 @@ write_again: goto write_again; break; - case DMA_INITIATOR_RECEIVE: + case DMA_IN_TX_BUS: if (!(t128->status & 0x04)) { t128_log("Read status busy, block count = %i, host pos = %i\n", t128->block_count, t128->host_pos); break; @@ -318,19 +325,19 @@ write_again: read_again: for (c = 0; c < 10; c++) { - ncr5380_bus_read(ncr); - if (ncr->cur_bus & BUS_REQ) + status = scsi_bus_read(scsi_bus); + if (status & BUS_REQ) break; } /* Data ready. */ - ncr5380_bus_read(ncr); - temp = BUS_GETDATA(ncr->cur_bus); + bus = scsi_bus_read(scsi_bus); + temp = BUS_GETDATA(bus); bus = ncr5380_get_bus_host(ncr); - ncr5380_bus_update(ncr, bus | BUS_ACK); - ncr5380_bus_update(ncr, bus & ~BUS_ACK); + scsi_bus_update(scsi_bus, bus | BUS_ACK); + scsi_bus_update(scsi_bus, bus & ~BUS_ACK); t128->buffer[t128->pos++] = temp; t128_log("T128 Buffer pos for reading=%d, temp=%02x, len=%d.\n", t128->pos, temp, dev->buffer_length); @@ -360,12 +367,12 @@ read_again: break; } - ncr5380_bus_read(ncr); + status = scsi_bus_read(scsi_bus); - if (!(ncr->cur_bus & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) { + if (!(status & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) { t128_log("Updating DMA\n"); ncr->mode &= ~MODE_DMA; - ncr->dma_mode = DMA_IDLE; + scsi_bus->tx_mode = PIO_TX_BUS; timer_on_auto(&t128->timer, 10.0); } } @@ -467,12 +474,14 @@ t128_init(const device_t *info) { t128_t *t128; ncr_t *ncr; + scsi_bus_t *scsi_bus; t128 = malloc(sizeof(t128_t)); memset(t128, 0x00, sizeof(t128_t)); ncr = &t128->ncr; ncr->bus = scsi_get_bus(); + scsi_bus = &ncr->scsibus; if (info->flags & DEVICE_MCA) { rom_init(&t128->bios_rom, T128_ROM, @@ -504,6 +513,9 @@ t128_init(const device_t *info) ncr->dma_send_ext = t128_dma_send_ext; ncr->dma_initiator_receive_ext = t128_dma_initiator_receive_ext; ncr->timer = t128_timer_on_auto; + scsi_bus->bus_device = ncr->bus; + scsi_bus->timer = ncr->timer; + scsi_bus->priv = ncr->priv; t128->status = 0x00 /*0x04*/; t128->host_pos = 512; if (!t128->bios_enabled && !(info->flags & DEVICE_MCA)) @@ -516,6 +528,9 @@ t128_init(const device_t *info) timer_add(&t128->timer, t128_callback, t128, 0); scsi_bus_set_speed(ncr->bus, 5000000.0); + scsi_bus->speed = 0.2; + scsi_bus->divider = 1.0; + scsi_bus->multi = 1.0; return t128; } diff --git a/src/sound/snd_pas16.c b/src/sound/snd_pas16.c index ed82afebf..110ee95c9 100644 --- a/src/sound/snd_pas16.c +++ b/src/sound/snd_pas16.c @@ -86,7 +86,7 @@ * Copyright 2008-2024 Sarah Walker. * Copyright 2024 Miran Grca. */ -#define _USE_MATH_DEFINES +#define _USE_MATH_DEFINES #include #include #include @@ -706,6 +706,7 @@ static uint8_t pas16_in(uint16_t port, void *priv) { pas16_t *pas16 = (pas16_t *) priv; + scsi_bus_t *scsi_bus = NULL; uint8_t ret = 0xff; port -= pas16->base; @@ -784,9 +785,11 @@ pas16_in(uint16_t port, void *priv) ret = t128_read(0x1e00, pas16->scsi); break; case 0x5c01: - if (pas16->has_scsi) + if (pas16->has_scsi) { + scsi_bus = &pas16->scsi->ncr.scsibus; /* Bits 0-6 must absolutely be set for SCSI hard disk drivers to work. */ - ret = (((pas16->scsi->ncr.dma_mode != DMA_IDLE) && (pas16->scsi->status & 0x04)) << 7) | 0x7f; + ret = (((scsi_bus->tx_mode != PIO_TX_BUS) && (pas16->scsi->status & 0x04)) << 7) | 0x7f; + } break; case 0x5c03: if (pas16->has_scsi) @@ -1183,10 +1186,11 @@ pas16_scsi_callback(void *priv) { pas16_t * pas16 = (pas16_t *) priv; t128_t * dev = pas16->scsi; + scsi_bus_t * scsi_bus = &dev->ncr.scsibus; t128_callback(pas16->scsi); - if ((dev->ncr.dma_mode != DMA_IDLE) && (dev->status & 0x04)) { + if ((scsi_bus->tx_mode != PIO_TX_BUS) && (dev->status & 0x04)) { timer_stop(&pas16->scsi_timer); pas16->timeout_status &= 0x7f; }