From efe9784aad8dfc742330ae20e95d550ecc3c2574 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 19 Dec 2023 11:42:01 +0600 Subject: [PATCH 1/4] MGA: Count for cases where DMA header data is not immediately available Fixes crashes on NT 4.0 --- src/video/vid_mga.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/video/vid_mga.c b/src/video/vid_mga.c index 2c9561b02..2d4d3be02 100644 --- a/src/video/vid_mga.c +++ b/src/video/vid_mga.c @@ -15,6 +15,7 @@ * Copyright 2008-2020 Sarah Walker. */ #include +#include #include #include #include @@ -512,6 +513,8 @@ typedef struct mystique_t { pri_header, sec_header, iload_header; + bool words_expected, sec_words_expected; + mutex_t *lock; } dma; @@ -2664,13 +2667,21 @@ run_dma(mystique_t *mystique) case DMA_STATE_PRI: switch (mystique->dma.primaddress & DMA_MODE_MASK) { case DMA_MODE_REG: - if (mystique->dma.pri_state == 0) { + if (mystique->dma.pri_state == 0 && !mystique->dma.words_expected) { dma_bm_read(mystique->dma.primaddress & DMA_ADDR_MASK, (uint8_t *) &mystique->dma.pri_header, 4, 4); mystique->dma.primaddress += 4; words_transferred++; } - if ((mystique->dma.pri_header & 0xff) != 0x15 && (mystique->dma.primaddress & DMA_ADDR_MASK) < (mystique->dma.primend & DMA_ADDR_MASK)) { + if ((mystique->dma.primaddress & DMA_ADDR_MASK) >= (mystique->dma.primend & DMA_ADDR_MASK) && !mystique->dma.words_expected) + { + /* Wait until more data is available. */ + mystique->dma.words_expected = 1; + break; + } + + mystique->dma.words_expected = 0; + if ((mystique->dma.pri_header & 0xff) != 0x15) { uint32_t val; uint32_t reg_addr; @@ -2709,7 +2720,7 @@ run_dma(mystique_t *mystique) case DMA_STATE_SEC: switch (mystique->dma.secaddress & DMA_MODE_MASK) { case DMA_MODE_REG: - if (mystique->dma.sec_state == 0) { + if (mystique->dma.sec_state == 0 && !mystique->dma.sec_words_expected) { dma_bm_read(mystique->dma.secaddress & DMA_ADDR_MASK, (uint8_t *) &mystique->dma.sec_header, 4, 4); mystique->dma.secaddress += 4; words_transferred++; @@ -2718,6 +2729,14 @@ run_dma(mystique_t *mystique) uint32_t val; uint32_t reg_addr; + if ((mystique->dma.secaddress & DMA_ADDR_MASK) >= (mystique->dma.secend & DMA_ADDR_MASK) && !mystique->dma.sec_words_expected) + { + /* Wait until more data is available. */ + mystique->dma.sec_words_expected = 1; + break; + } + + mystique->dma.sec_words_expected = 0; dma_bm_read(mystique->dma.secaddress & DMA_ADDR_MASK, (uint8_t *) &val, 4, 4); mystique->dma.secaddress += 4; From 3ba6e337c5cc0ca61357e9b97ceb867c1db67e5d Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 19 Dec 2023 12:02:58 +0600 Subject: [PATCH 2/4] Revert "MGA: Count for cases where DMA header data is not immediately available" This reverts commit efe9784aad8dfc742330ae20e95d550ecc3c2574. --- src/video/vid_mga.c | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/src/video/vid_mga.c b/src/video/vid_mga.c index 2d4d3be02..2c9561b02 100644 --- a/src/video/vid_mga.c +++ b/src/video/vid_mga.c @@ -15,7 +15,6 @@ * Copyright 2008-2020 Sarah Walker. */ #include -#include #include #include #include @@ -513,8 +512,6 @@ typedef struct mystique_t { pri_header, sec_header, iload_header; - bool words_expected, sec_words_expected; - mutex_t *lock; } dma; @@ -2667,21 +2664,13 @@ run_dma(mystique_t *mystique) case DMA_STATE_PRI: switch (mystique->dma.primaddress & DMA_MODE_MASK) { case DMA_MODE_REG: - if (mystique->dma.pri_state == 0 && !mystique->dma.words_expected) { + if (mystique->dma.pri_state == 0) { dma_bm_read(mystique->dma.primaddress & DMA_ADDR_MASK, (uint8_t *) &mystique->dma.pri_header, 4, 4); mystique->dma.primaddress += 4; words_transferred++; } - if ((mystique->dma.primaddress & DMA_ADDR_MASK) >= (mystique->dma.primend & DMA_ADDR_MASK) && !mystique->dma.words_expected) - { - /* Wait until more data is available. */ - mystique->dma.words_expected = 1; - break; - } - - mystique->dma.words_expected = 0; - if ((mystique->dma.pri_header & 0xff) != 0x15) { + if ((mystique->dma.pri_header & 0xff) != 0x15 && (mystique->dma.primaddress & DMA_ADDR_MASK) < (mystique->dma.primend & DMA_ADDR_MASK)) { uint32_t val; uint32_t reg_addr; @@ -2720,7 +2709,7 @@ run_dma(mystique_t *mystique) case DMA_STATE_SEC: switch (mystique->dma.secaddress & DMA_MODE_MASK) { case DMA_MODE_REG: - if (mystique->dma.sec_state == 0 && !mystique->dma.sec_words_expected) { + if (mystique->dma.sec_state == 0) { dma_bm_read(mystique->dma.secaddress & DMA_ADDR_MASK, (uint8_t *) &mystique->dma.sec_header, 4, 4); mystique->dma.secaddress += 4; words_transferred++; @@ -2729,14 +2718,6 @@ run_dma(mystique_t *mystique) uint32_t val; uint32_t reg_addr; - if ((mystique->dma.secaddress & DMA_ADDR_MASK) >= (mystique->dma.secend & DMA_ADDR_MASK) && !mystique->dma.sec_words_expected) - { - /* Wait until more data is available. */ - mystique->dma.sec_words_expected = 1; - break; - } - - mystique->dma.sec_words_expected = 0; dma_bm_read(mystique->dma.secaddress & DMA_ADDR_MASK, (uint8_t *) &val, 4, 4); mystique->dma.secaddress += 4; From 1f91c0e2ec22d0122f15cb12e754ccbbdd0f4eb1 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 19 Dec 2023 12:59:18 +0600 Subject: [PATCH 3/4] More work on busmastering NT 4.0 freezes as of now. No idea, although the data aren't filled with total nonsense anymore --- src/video/vid_mga.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/src/video/vid_mga.c b/src/video/vid_mga.c index 2c9561b02..1cba098ef 100644 --- a/src/video/vid_mga.c +++ b/src/video/vid_mga.c @@ -512,6 +512,8 @@ typedef struct mystique_t { pri_header, sec_header, iload_header; + atomic_uint words_expected; + mutex_t *lock; } dma; @@ -2435,7 +2437,7 @@ mystique_ctrl_write_l(uint32_t addr, uint32_t val, void *priv) mystique->status &= ~STATUS_ENDPRDMASTS; mystique->dma.state = DMA_STATE_PRI; - mystique->dma.pri_state = 0; + //mystique->dma.pri_state = 0; wake_fifo_thread(mystique); } thread_release_mutex(mystique->dma.lock); @@ -2664,19 +2666,32 @@ run_dma(mystique_t *mystique) case DMA_STATE_PRI: switch (mystique->dma.primaddress & DMA_MODE_MASK) { case DMA_MODE_REG: - if (mystique->dma.pri_state == 0) { + if ((mystique->dma.primaddress & DMA_ADDR_MASK) >= (mystique->dma.primend & DMA_ADDR_MASK)) { + mystique->endprdmasts_pending = 1; + mystique->dma.state = DMA_STATE_IDLE; + break; + } + if (mystique->dma.pri_state == 0 && !mystique->dma.words_expected) { dma_bm_read(mystique->dma.primaddress & DMA_ADDR_MASK, (uint8_t *) &mystique->dma.pri_header, 4, 4); mystique->dma.primaddress += 4; + pclog("DMA header: 0x%08X\n", mystique->dma.pri_header); + mystique->dma.words_expected = 4; words_transferred++; } - if ((mystique->dma.pri_header & 0xff) != 0x15 && (mystique->dma.primaddress & DMA_ADDR_MASK) < (mystique->dma.primend & DMA_ADDR_MASK)) { + if ((mystique->dma.primaddress & DMA_ADDR_MASK) >= (mystique->dma.primend & DMA_ADDR_MASK)) { + mystique->endprdmasts_pending = 1; + mystique->dma.state = DMA_STATE_IDLE; + break; + } + + if ((mystique->dma.pri_header & 0xff) != 0x15) { uint32_t val; uint32_t reg_addr; dma_bm_read(mystique->dma.primaddress & DMA_ADDR_MASK, (uint8_t *) &val, 4, 4); - mystique->dma.primaddress += 4; words_transferred++; + pclog("DMA val: 0x%08X\n", val); reg_addr = (mystique->dma.pri_header & 0x7f) << 2; if (mystique->dma.pri_header & 0x80) @@ -2690,6 +2705,10 @@ run_dma(mystique_t *mystique) mystique_accel_ctrl_write_l(reg_addr, val, mystique); } + if (mystique->dma.words_expected) + mystique->dma.words_expected--; + mystique->dma.primaddress += 4; + mystique->dma.pri_header >>= 8; mystique->dma.pri_state = (mystique->dma.pri_state + 1) & 3; @@ -2740,8 +2759,11 @@ run_dma(mystique_t *mystique) if ((mystique->dma.primaddress & DMA_ADDR_MASK) >= (mystique->dma.primend & DMA_ADDR_MASK)) { mystique->endprdmasts_pending = 1; mystique->dma.state = DMA_STATE_IDLE; - } else + } else{ mystique->dma.state = DMA_STATE_PRI; + mystique->dma.words_expected = 0; + mystique->dma.pri_state = 0; + } } break; @@ -2760,8 +2782,11 @@ run_dma(mystique_t *mystique) if ((mystique->dma.primaddress & DMA_ADDR_MASK) >= (mystique->dma.primend & DMA_ADDR_MASK)) { mystique->endprdmasts_pending = 1; mystique->dma.state = DMA_STATE_IDLE; - } else + } else { mystique->dma.state = DMA_STATE_PRI; + mystique->dma.words_expected = 0; + mystique->dma.pri_state = 0; + } } } break; From 3a5bbe9ad391bfb7647b863714fe6f25ae51ca1d Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 19 Dec 2023 13:46:27 +0600 Subject: [PATCH 4/4] vid_mga: Busmastering works properly now --- src/video/vid_mga.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/video/vid_mga.c b/src/video/vid_mga.c index 1cba098ef..bf73206dc 100644 --- a/src/video/vid_mga.c +++ b/src/video/vid_mga.c @@ -2674,7 +2674,6 @@ run_dma(mystique_t *mystique) if (mystique->dma.pri_state == 0 && !mystique->dma.words_expected) { dma_bm_read(mystique->dma.primaddress & DMA_ADDR_MASK, (uint8_t *) &mystique->dma.pri_header, 4, 4); mystique->dma.primaddress += 4; - pclog("DMA header: 0x%08X\n", mystique->dma.pri_header); mystique->dma.words_expected = 4; words_transferred++; } @@ -2685,13 +2684,12 @@ run_dma(mystique_t *mystique) break; } - if ((mystique->dma.pri_header & 0xff) != 0x15) { + { uint32_t val; uint32_t reg_addr; dma_bm_read(mystique->dma.primaddress & DMA_ADDR_MASK, (uint8_t *) &val, 4, 4); words_transferred++; - pclog("DMA val: 0x%08X\n", val); reg_addr = (mystique->dma.pri_header & 0x7f) << 2; if (mystique->dma.pri_header & 0x80) @@ -2712,8 +2710,10 @@ run_dma(mystique_t *mystique) mystique->dma.pri_header >>= 8; mystique->dma.pri_state = (mystique->dma.pri_state + 1) & 3; - if (mystique->dma.state == DMA_STATE_SEC) - mystique->dma.pri_state = 0; + if (mystique->dma.state == DMA_STATE_SEC) { + mystique->dma.pri_state = 0; + mystique->dma.words_expected = 0; + } else if ((mystique->dma.primaddress & DMA_ADDR_MASK) >= (mystique->dma.primend & DMA_ADDR_MASK)) { mystique->endprdmasts_pending = 1; mystique->dma.state = DMA_STATE_IDLE;