Skip to content

Commit

Permalink
Added -R WDC soft reset command (hard reset not implemented by A3000 HW)
Browse files Browse the repository at this point in the history
Implemented ReSDMAC version reporting
Added ReSDMAC version register display
Added creation of zip, lha, and adf files to the Makefile
Changed SDMAC/Ramsey shadow register offset for A3000+ compatibility
  • Loading branch information
Chris Hooper committed Jul 26, 2024
1 parent 74b4b37 commit 95fe7a1
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 41 deletions.
44 changes: 41 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@
# make
#
PROGS := sdmac

VER := $(shell awk '/\$$VER:/{print $$7}' sdmac.c)
ADF_FILE := sdmac_$(VER).adf
ZIP_FILE := sdmac_$(VER).zip
LHA_FILE := sdmac_$(VER).lha
ARC_DIR := sdmac_$(VER)

CC := m68k-amigaos-gcc
CFLAGS := -Wall -Wno-pointer-sign -Os

Expand All @@ -21,18 +28,49 @@ ifeq (, $(shell which $(CC) 2>/dev/null ))
$(error "No $(CC) in PATH: maybe do PATH=$$PATH:/opt/amiga/bin to set up")
endif

ifeq (, $(shell which xdftool 2>/dev/null ))
$(error "No xdftool in PATH: build and install amitools first: https://github.com/cnvogelg/amitools")
endif

all: $(PROGS)

sdmac: sdmac.c

$(PROGS): Makefile
$(CC) $(CFLAGS) $(filter %.c,$^) -o $@ $(LDFLAGS)

zip: sdmac.zip
zip: $(ZIP_FILE)
lha: $(LHA_FILE)

sdmac.zip: sdmac
$(ZIP_FILE): $(PROGS) README.md LICENSE
rm -rf $(ARC_DIR)
mkdir $(ARC_DIR)
cp -p $^ $(ARC_DIR)/
rm -f $@
zip $@ $<
zip -r $@ $(ARC_DIR)
rm -rf $(ARC_DIR)

$(LHA_FILE): $(PROGS) README.md LICENSE
rm -rf $(ARC_DIR)
mkdir $(ARC_DIR)
cp -p $^ $(ARC_DIR)/
rm -f $@
lha a $@ $(ARC_DIR)
rm -rf $(ARC_DIR)

adf: $(PROGS)
echo $(ADF_FILE)
xdftool $(ADF_FILE) format "AmigaSDMAC"
xdftool $(ADF_FILE) makedir C
xdftool $(ADF_FILE) makedir S
xdftool $(ADF_FILE) makedir Devs
xdftool $(ADF_FILE) write sdmac C/sdmac
xdftool $(ADF_FILE) write disk/Startup-Sequence S/Startup-Sequence
xdftool $(ADF_FILE) write disk/system-configuration Devs/system-configuration
xdftool $(ADF_FILE) write disk/Disk.info
xdftool $(ADF_FILE) write README.md
xdftool $(ADF_FILE) write LICENSE
xdftool $(ADF_FILE) boot install

clean:
rm $(PROGS)
Binary file added disk/Disk.info
Binary file not shown.
8 changes: 8 additions & 0 deletions disk/Startup-Sequence
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
; Startup-Sequence
; Copyright � 2024 Chris Hooper

Path SYS:C ADD

echo "Welcome to the SDMAC test utility disk"
echo ""
echo "For command options, type: sdmac ?"
Binary file added disk/system-configuration
Binary file not shown.
178 changes: 140 additions & 38 deletions sdmac.c
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
/*
* SDMAC Version 0.5 2023-09-25
* SDMAC Version 0.6 2024-07-26
* -----------------------------
* Utility to inspect and test an Amiga 3000's Super DMAC (SDMAC),
* WD SCSI controller for correct configuration and operation.
*
* Copyright 2023 Chris Hooper. This program and source may be used
* and distributed freely, for any purpose which benefits the Amiga
* community. Commercial use of the binary, source, or algorithms requires
* prior written or email approval from Chris Hooper <[email protected]>.
* Copyright Chris Hooper. This program and source may be used and
* distributed freely, for any purpose which benefits the Amiga community.
* Commercial use of the binary, source, or algorithms requires prior
* written or email approval from Chris Hooper <[email protected]>.
* All redistributions must retain this Copyright notice.
*
* DISCLAIMER: THE SOFTWARE IS PROVIDED "AS-IS", WITHOUT ANY WARRANTY.
* THE AUTHOR ASSUMES NO LIABILITY FOR ANY DAMAGE ARISING OUT OF THE USE
* OR MISUSE OF THIS UTILITY OR INFORMATION REPORTED BY THIS UTILITY.
*/
const char *version = "\0$VER: SDMAC 0.5 ("__DATE__") © Chris Hooper";
const char *version = "\0$VER: SDMAC 0.6 ("__DATE__") © Chris Hooper";

#include <stdio.h>
#include <stdlib.h>
Expand All @@ -38,6 +38,7 @@
#define SDMAC_BASE 0x00DD0000 // Base address of SDMAC
#define SDMAC_DAWR 0x00DD0003 // Write DACK width register (write)
#define SDMAC_WTC 0x00DD0004 // R/W Word Transfer Count (SDMAC-02 only)
#define SDMAC_CNTR 0x00DD0008 // R/W Control Register (byte) from doc
#define SDMAC_CONTR 0x00DD000b // R/W Control Register (byte)
#define RAMSEY_ACR 0x00DD000C // R/W DMA Control Register (in Ramsey)
#define SDMAC_ST_DMA 0x00DD0013 // Strobe Start DMA (write 0 to start)
Expand All @@ -58,9 +59,9 @@
#define SDMAC_SSPBDAT 0x00DD0058 // R/W Sync. Serial Periph. Bus Data (long)
#define SDMAC_SSPBCTL 0x00DD005C // R/W Sync. Serial Periph. Bus Ctrl (long)

#define SDMAC_WTC_ALT (SDMAC_WTC + 0x80) // Shadow of SDMAC WTC
#define RAMSEY_ACR_ALT (RAMSEY_ACR + 0x80) // Shadow of Ramsey ACR
#define SDMAC_SSPBDAT_ALT (SDMAC_SSPBDAT + 0x80) // Shadow of SDMAC SSPBDAT
#define SDMAC_WTC_ALT (SDMAC_WTC + 0x100) // Shadow of SDMAC WTC
#define RAMSEY_ACR_ALT (RAMSEY_ACR + 0x100) // Shadow of Ramsey ACR
#define SDMAC_SSPBDAT_ALT (SDMAC_SSPBDAT + 0x100) // Shadow of SDMAC SSPBDAT

#define WDC_ADDR 0x00 // Write WDC Address Register
#define WDC_OWN_ID 0x00 // R/W Own ID
Expand Down Expand Up @@ -94,6 +95,8 @@

#define WDC_INVALID_REG 0x1e // Not a real WD register

#define WDC_CMD_RESET 0x00 // Soft reset the WDC controller

/* Interrupt status register */
#define SDMAC_ISTR_FIFOE 0x01 // FIFO Empty
#define SDMAC_ISTR_FIFOF 0x02 // FIFO Full
Expand All @@ -109,7 +112,7 @@
#define SDMAC_CONTR_DMADIR 0x02 // DMA Data direction (0=Read, 1=Write)
#define SDMAC_CONTR_INTEN 0x04 // Interrupt enable
//#define SDMAC_CONTR_PMODE 0x08 // Peripheral mode (1=SCSI)
#define SDMAC_CONTR_RESET 0x10 // Peripheral reset (Strobe)
#define SDMAC_CONTR_RESET 0x10 // WDC Peripheral reset (Strobe)
#define SDMAC_CONTR_TCE 0x20 // Terminal count enable
//#define SDMAC_CONTR_0x40 0x40 // Reserved (6)
//#define SDMAC_CONTR_0x80 0x80 // Reserved (7)
Expand Down Expand Up @@ -231,29 +234,30 @@ typedef struct {
} reglist_t;

static const reglist_t sdmac_reglist[] = {
{ RAMSEY_CTRL, BYTE, RW, "Ramsey_CTRL", "Ramsey Control" },
{ RAMSEY_VER, BYTE, RW, "Ramsey_VER", "Ramsey Version" },
{ SDMAC_DAWR, BYTE, WO, "SDMAC_DAWR", "DACK width register (WO)" },
{ SDMAC_WTC, LONG, RW, "SDMAC_WTC", "Word Transfer Count" },
{ SDMAC_CONTR, BYTE, RW, "SDMAC_CONTR", "Control Register" },
{ RAMSEY_ACR, LONG, RW, "Ramsey_ACR", "DMA Address Register" },
{ SDMAC_ST_DMA, BYTE, WO, "SDMAC_ST_DMA", "Start DMA" },
{ SDMAC_FLUSH, BYTE, WO, "SDMAC_FLUSH", "Flush DMA FIFO" },
{ SDMAC_CLR_INT, BYTE, WO, "SDMAC_CLR_INT", "Clear Interrupts" },
{ SDMAC_ISTR, BYTE, RO, "SDMAC_ISTR", "Interrupt Status Register" },
{ SDMAC_SP_DMA, BYTE, WO, "SDMAC_SP_DMA", "Stop DMA" },
{ SDMAC_SASR_L, LONG, WO, "SDMAC_SASR_L", "WDC register index" },
{ SDMAC_SASR_B, BYTE, RO, "SDMAC_SASR_B", "WDC register index" },
{ SDMAC_SCMD, BYTE, RW, "SDMAC_SCMD", "WDC register data" },
{ SDMAC_SASRW, LONG, WO, "SDMAC_SASRW", "WDC register index" },
{ SDMAC_SASR_B2, BYTE, RW, "SDMAC_SASR_B", "WDC register index" },
{ SDMAC_CI, LONG, RW, "SDMAC_CI",
{ RAMSEY_CTRL, BYTE, RW, "Ramsey_CTRL", "Ramsey Control" },
{ RAMSEY_VER, BYTE, RW, "Ramsey_VER", "Ramsey Version" },
{ SDMAC_DAWR, BYTE, WO, "SDMAC_DAWR", "DACK width register (WO)" },
{ SDMAC_WTC, LONG, RW, "SDMAC_WTC", "Word Transfer Count" },
{ SDMAC_CONTR, BYTE, RW, "SDMAC_CONTR", "Control Register" },
{ RAMSEY_ACR, LONG, RW, "Ramsey_ACR", "DMA Address Register" },
{ SDMAC_ST_DMA, BYTE, WO, "SDMAC_ST_DMA", "Start DMA" },
{ SDMAC_FLUSH, BYTE, WO, "SDMAC_FLUSH", "Flush DMA FIFO" },
{ SDMAC_CLR_INT, BYTE, WO, "SDMAC_CLR_INT", "Clear Interrupts" },
{ SDMAC_ISTR, BYTE, RO, "SDMAC_ISTR", "Interrupt Status Register" },
{ SDMAC_REVISION, LONG, RO, "SDMAC_REVISION", "ReSDMAC revision" },
{ SDMAC_SP_DMA, BYTE, WO, "SDMAC_SP_DMA", "Stop DMA" },
{ SDMAC_SASR_L, LONG, WO, "SDMAC_SASR_L", "WDC register index" },
{ SDMAC_SASR_B, BYTE, RO, "SDMAC_SASR_B", "WDC register index" },
{ SDMAC_SCMD, BYTE, RW, "SDMAC_SCMD", "WDC register data" },
{ SDMAC_SASRW, LONG, WO, "SDMAC_SASRW", "WDC register index" },
{ SDMAC_SASR_B2, BYTE, RW, "SDMAC_SASR_B", "WDC register index" },
{ SDMAC_CI, LONG, RW, "SDMAC_CI",
"Coprocessor Interface Register" },
{ SDMAC_CIDDR, LONG, RW, "SDMAC_CIDDR",
{ SDMAC_CIDDR, LONG, RW, "SDMAC_CIDDR",
"Coprocessor Interface Data Direction Register" },
{ SDMAC_SSPBCTL, LONG, RW, "SDMAC_SSPBCTL",
{ SDMAC_SSPBCTL, LONG, RW, "SDMAC_SSPBCTL",
"Synchronous Serial Peripheral Bus Control Register"},
{ SDMAC_SSPBDAT, LONG, RW, "SDMAC_SSPBDAT",
{ SDMAC_SSPBDAT, LONG, RW, "SDMAC_SSPBDAT",
"Synchronous Serial Peripheral Bus Data Register "},
};

Expand Down Expand Up @@ -568,7 +572,7 @@ show_regs(void)
{
int pos;
uint32_t value;
printf("\nREG VALUE NAME DESCRIPTION\n");
printf("\nREG VALUE NAME DESCRIPTION\n");
for (pos = 0; pos < ARRAY_SIZE(sdmac_reglist); pos++) {
if (sdmac_reglist[pos].type == WO)
continue; // Skip this register
Expand All @@ -586,19 +590,19 @@ show_regs(void)
break;
}
SUPERVISOR_STATE_EXIT(); // Needed for RAMSEY_VER register
printf(" %02x %0*x%*s %-13s %s\n",
printf(" %02x %0*x%*s %-14s %s\n",
sdmac_reglist[pos].addr & 0xff,
sdmac_reglist[pos].width * 2, value,
8 - sdmac_reglist[pos].width * 2, "",
sdmac_reglist[pos].name, sdmac_reglist[pos].desc);
}

printf("REG VALUE NAME DESCRIPTION\n");
printf("REG VALUE NAME DESCRIPTION\n");
for (pos = 0; pos < ARRAY_SIZE(wd_reglist); pos++) {
if (wd_reglist[pos].type == WO)
continue; // Skip this register
value = get_wdc_reg(wd_reglist[pos].addr);
printf(" %02x %0*x%*s %-13s %s",
printf(" %02x %0*x%*s %-14s %s",
wd_reglist[pos].addr & 0xff,
wd_reglist[pos].width * 2, value,
8 - wd_reglist[pos].width * 2, "",
Expand All @@ -615,6 +619,84 @@ show_regs(void)
}
}

/* CIA_USEC rounds up 1 value to at least one CIA tick */
#define CIA_USEC(x) (((x) * 715909 + 284091) / 1000000)

#define CIAA_TBLO ADDR8(0x00bfe601)
#define CIAA_TBHI ADDR8(0x00bfe701)

static uint
cia_ticks(void)
{
uint8_t hi1;
uint8_t hi2;
uint8_t lo;

hi1 = *CIAA_TBHI;
lo = *CIAA_TBLO;
hi2 = *CIAA_TBHI;

/*
* The below operation will provide the same effect as:
* if (hi2 != hi1)
* lo = 0xff; // rollover occurred
*/
lo |= (hi2 - hi1); // rollover of hi forces lo to 0xff value

return (lo | (hi2 << 8));
}

void
cia_spin(unsigned int ticks)
{
uint16_t start = cia_ticks();
uint16_t now;
uint16_t diff;

while (ticks != 0) {
now = cia_ticks();
diff = start - now;
if (diff >= ticks)
break;
ticks -= diff;
start = now;
__asm__ __volatile__("nop");
__asm__ __volatile__("nop");
}
}

static void
wdc_hard_reset(void)
{
uint8_t value = *ADDR8(SDMAC_CNTR);
*ADDR8(SDMAC_CNTR) = 0; // Disable interrupts
cia_spin(CIA_USEC(2));
*ADDR8(SDMAC_CNTR) = SDMAC_CONTR_RESET;
cia_spin(CIA_USEC(2));
*ADDR8(SDMAC_CNTR) = 0;
cia_spin(CIA_USEC(2));
*ADDR8(SDMAC_CNTR) = value;
}

static void
wdc_soft_reset(void)
{
uint8_t wdc_own;
uint8_t wdc_new_own;

wdc_new_own = 0x40 | // Input clock divisor 3 (FS0) for 14 MHz clock
0x00 | // 0x04 to enable advanced features
0x07; // SCSI bus id

INTERRUPTS_DISABLE();
wdc_own = get_wdc_reg(WDC_OWN_ID);
set_wdc_reg(WDC_OWN_ID, wdc_new_own);
set_wdc_reg(WDC_CMD, WDC_CMD_RESET);
cia_spin(CIA_USEC(30));
set_wdc_reg(WDC_OWN_ID, wdc_own);
INTERRUPTS_ENABLE();
}

__attribute__((noinline))
uint8_t
get_sdmac_version(void)
Expand Down Expand Up @@ -734,20 +816,26 @@ show_ramsey_version(void)
}

static uint8_t sdmac_version = 0;
static uint8_t sdmac_version_rev = 0;
static uint32_t sdmac_version_rev = 0;

static uint
show_dmac_version(void)
{
sdmac_version = get_sdmac_version();
sdmac_version_rev = (sdmac_version == 4) ? *ADDR8(SDMAC_REVISION) : 0;
sdmac_version_rev = *ADDR32(SDMAC_REVISION); // ReSDMAC only

switch (sdmac_version) {
case 2:
case 4:
printf("SCSI DMA Controller: SDMAC-%02d", sdmac_version);
if ((sdmac_version_rev != 0x00) && (sdmac_version_rev != 0xff))
printf(" Rev %02x\n", sdmac_version_rev);
if (((char)(sdmac_version_rev >> 24) == 'R') &&
((char)(sdmac_version_rev >> 16) == 'E')) {
printf(" %c%c%c%c",
(char) (sdmac_version_rev >> 24),
(char) (sdmac_version_rev >> 16),
(char) (sdmac_version_rev >> 8),
(char) sdmac_version_rev);
}
printf("\n");
return (0);
default:
Expand Down Expand Up @@ -1355,6 +1443,7 @@ test_wdc_access(void)
int
main(int argc, char **argv)
{
int do_wdc_reset = 0;
int raw_sdmac_regs = 0;
int all_regs = 0;
int loop_until_failure = 0;
Expand All @@ -1374,6 +1463,9 @@ main(int argc, char **argv)
case 'r':
all_regs++;
break;
case 'R':
do_wdc_reset++;
break;
case 's':
raw_sdmac_regs++;
break;
Expand All @@ -1392,6 +1484,7 @@ main(int argc, char **argv)
printf("%s\nOptions:\n"
" -d Debug output\n"
" -L Loop tests until failure\n"
" -R reset WD SCSI Controller\n"
" -r Display registers\n"
" -s Display raw SDMAC registers\n"
" -t Force tests to run\n"
Expand All @@ -1401,6 +1494,15 @@ main(int argc, char **argv)
}

BERR_DSACK_SAVE();
if (do_wdc_reset) {
if (do_wdc_reset > 1) {
wdc_hard_reset();
} else {
wdc_soft_reset();
}
printf("WDC %s reset complete\n", (do_wdc_reset > 1) ? "hard" : "soft");
goto finish;
}
if (show_ramsey_version() ||
show_ramsey_config() ||
show_dmac_version() ||
Expand Down

0 comments on commit 95fe7a1

Please sign in to comment.