Browse Source

abcio: make ABC I/O devices configurable

Make I/O devices configurable at the FPGA level.
H. Peter Anvin 1 year ago
parent
commit
33f209e48c

+ 15 - 1
common/sysvars.vars

@@ -1,7 +1,21 @@
 @config
 LANG			str "sv"
 TZ			tz "CET-1CEST,M3.5.0,M10.5.0/3"
-abc.hosttype		uint
+abc.io.mo.enable	bool false
+abc.io.mo.devsel	uint 45
+abc.io.mf.enable	bool false
+abc.io.mf.devsel	uint 44
+abc.io.sf.enable	bool false
+abc.io.sf.devsel	uint 46
+abc.io.hd.enable	bool true
+abc.io.hd.devsel	uint 36
+abc.io.xd.enable	bool false
+abc.io.xd.devsel	uint 37
+abc.io.rtc.enable	bool true
+abc.io.rtc.devsel	uint 54
+abc.io.pun80.enable	bool true
+abc.io.pun80.devsel	uint 60
+abc.hosttype		uint 0
 abc.reset		bool
 fpga.reset		bool
 hostname		str "max80"

BIN
esp32/output/max80.ino.bin


+ 3 - 3
fpga/max80.qpf

@@ -19,15 +19,15 @@
 #
 # Quartus Prime
 # Version 22.1std.0 Build 915 10/25/2022 SC Lite Edition
-# Date created = 17:09:07  September 05, 2023
+# Date created = 18:16:12  September 05, 2023
 #
 # -------------------------------------------------------------------------- #
 
 QUARTUS_VERSION = "22.1"
-DATE = "17:09:07  September 05, 2023"
+DATE = "18:16:12  September 05, 2023"
 
 # Revisions
 
-PROJECT_REVISION = "v2"
 PROJECT_REVISION = "v1"
+PROJECT_REVISION = "v2"
 PROJECT_REVISION = "bypass"

BIN
fpga/output/bypass.jic


BIN
fpga/output/max80.fw


BIN
fpga/output/v1.fw


BIN
fpga/output/v1.jic


BIN
fpga/output/v1.sof


BIN
fpga/output/v2.fw


BIN
fpga/output/v2.jic


BIN
fpga/output/v2.sof


+ 46 - 11
rv32/abcdisk.c

@@ -8,6 +8,7 @@
 #include <stdio.h>
 
 #include "common.h"
+#include "config.h"
 #include "io.h"
 #include "abcio.h"
 #include "console.h"
@@ -65,8 +66,9 @@ struct drive_state {
 
 /* Fixed parameters for each controller */
 struct ctl_params {
+    enum sysvar_enum enable;    /* Enable configuration variable */
+    enum sysvar_enum devsel;	/* Device select code variable */
     uint8_t clustshift;		/* log2(clustersize/256) */
-    uint8_t devsel;		/* I/O device select */
     uint16_t maxsectors;	/* Maximum sectors for this controller */
     uint8_t c, h, s;		/* Disk geometry */
     bool newaddr;		/* "New addressing" */
@@ -86,7 +88,7 @@ struct ctl_state {
     uint8_t k[4];		/* Command bytes */
     uint8_t drives;		/* Total drives present */
     uint8_t error;		/* Error status */
-    bool initialized;	        /* Controller initialized */
+    bool initialized;		/* Controller initialized */
     volatile enum pending pending;	/* Need to do I/O */
     struct drive_state drv[8];	/* Per-drive state */
     uint8_t buf[4][256];	/* 4 host buffers @ 256 bytes */
@@ -110,6 +112,7 @@ enum controller_types {
     MFx,
     SFx,
     HDx,
+    XDx,
     CONTROLLER_TYPES
 };
 
@@ -127,7 +130,8 @@ static const struct ctl_params parameters[CONTROLLER_TYPES] = {
      * DSDD = 40×16×2 (320K, FD4D/DD84/DD52)
      */
     [MOx] = {
-	.devsel = 45,
+	.enable = config_abc_io_mo_enable,
+	.devsel = config_abc_io_mo_devsel,
 	.clustshift = 0,
 	.maxsectors = 40 * 2 * 16,
 	.c = 40, .h = 2, .s = 16,
@@ -140,7 +144,8 @@ static const struct ctl_params parameters[CONTROLLER_TYPES] = {
 
     /* MFx: DSQD = 80×16x2 (640K, ABC832/834) */
     [MFx] = {
-	.devsel = 44,
+	.enable = config_abc_io_mf_enable,
+	.devsel = config_abc_io_mf_devsel,
 	.clustshift = 2,
 	.maxsectors = 80 * 2 * 16,
 	.c = 80, .h = 2, .s = 16,
@@ -149,7 +154,8 @@ static const struct ctl_params parameters[CONTROLLER_TYPES] = {
 
     /* SFx: 8" floppy (DD88, ABC838) */
     [SFx] = {
-	.devsel = 46,
+	.enable = config_abc_io_sf_enable,
+	.devsel = config_abc_io_sf_devsel,
 	.clustshift = 2,
 	.maxsectors = (77 * 2 - 1) * 26, /* Track 0, side 0 not used */
 	.c = 77, .h = 2, .s = 26,
@@ -157,13 +163,25 @@ static const struct ctl_params parameters[CONTROLLER_TYPES] = {
     },
 
     [HDx] = {
-	.devsel = 36,
+	.enable = config_abc_io_hd_enable,
+	.devsel = config_abc_io_hd_devsel,
 	.clustshift = 5,
 	.newaddr = true,            /* Actually irrelevant for clustshift = 5 */
 	.maxsectors = (239 * 8 - 1) * 32,     /* Maximum supported by UFD-DOS */
 	.c = 238, .h = 16, .s = 64,
 	.name = "hd"
-    }
+    },
+
+    /* Second harddisk */
+    [XDx] = {
+	.enable = config_abc_io_xd_enable,
+	.devsel = config_abc_io_xd_devsel,
+	.clustshift = 5,
+	.newaddr = true,            /* Actually irrelevant for clustshift = 5 */
+	.maxsectors = (239 * 8 - 1) * 32,     /* Maximum supported by UFD-DOS */
+	.c = 238, .h = 16, .s = 64,
+	.name = "xd"
+    },
 };
 
 static struct ctl_state __dram_bss controllers[CONTROLLER_TYPES];
@@ -779,13 +797,30 @@ void abcdisk_init(void)
 	.callback_rst    = abcdisk_callback_rst
     };
 
-    for (int i = 0; i < CONTROLLER_TYPES; i++) {
+    for (size_t i = 0; i < CONTROLLER_TYPES; i++) {
 	struct ctl_state * const state = &controllers[i];
 
-	state->params = &parameters[i];
-	state->iodev  = iodev_template;
+	state->params      = &parameters[i];
+	state->iodev       = iodev_template;
+	state->iodev.name  = state->params->name;
 
 	disk_reset_state(state);
-	abc_register(&state->iodev, state->params->devsel);
+    }
+
+    abcdisk_config();
+}
+
+/*
+ * Called during initialization; can also be called on reconfig.
+ */
+void abcdisk_config(void)
+{
+    for (size_t i = 0; i < CONTROLLER_TYPES; i++) {
+	struct ctl_state * const state = &controllers[i];
+
+	unsigned int devsel = getvar_uint(state->params->devsel);
+	if (!getvar_bool(state->params->enable))
+	    devsel = DEVSEL_NONE;
+	abc_register(&state->iodev, devsel);
     }
 }

+ 45 - 7
rv32/abcio.c

@@ -8,6 +8,7 @@
 #include "io.h"
 #include "irq.h"
 #include "abcio.h"
+#include "console.h"
 
 __sbss struct abc_dev *_abc_selected_dev;
 static __bss_hot struct abc_dev *abc_device[65]; /* 65 == post-RST# = always NULL */
@@ -189,19 +190,56 @@ void __hot abc_set_inp_status(struct abc_dev *dev, uint8_t val)
  */
 void abc_register(struct abc_dev *dev, unsigned int devsel)
 {
-    if (devsel > 63)
-	return;
+    if (devsel >= DEVSEL_NONE)
+	devsel = DEVSEL_NONE;
 
     irqmask_t irqmask = mask_irq(ABC_IRQ);
+    unsigned int old_devsel = DEVSEL_NONE;
 
-    if (dev && !dev->inp_cnt)
-	dev->inp_data[0] = dev->inp_data_def;
+    if (dev) {
+	if (dev->devsel < DEVSEL_NONE && abc_device[dev->devsel] == dev) {
+	    old_devsel = dev->devsel;
+	    if (old_devsel == devsel)
+		goto done;	/* Already registered at this address */
+	    abc_device[old_devsel] = NULL;
+	    if (old_devsel == abc_devsel)
+		abc_select(NULL);
+	}
+	dev->devsel = devsel;
+	if (!dev->inp_cnt)
+	    dev->inp_data[0] = dev->inp_data_def;
+    }
 
-    abc_device[devsel] = dev;
-    if (devsel == abc_devsel)
-	abc_select(dev);
+    if (devsel < DEVSEL_NONE) {
+	if (abc_device[devsel])
+	    abc_device[devsel]->devsel = DEVSEL_NONE;
 
+	abc_device[devsel] = dev;
+	if (devsel == abc_devsel)
+	    abc_select(dev);
+    }
+
+done:
     restore_irq(irqmask, ABC_IRQ);
+
+    if (dev) {
+	if (old_devsel < DEVSEL_NONE) {
+	    if (devsel < DEVSEL_NONE) {
+		con_printf("[ABC] Moved device %s from devsel %u to %u\n",
+			   dev->name, old_devsel, devsel);
+	    } else {
+		con_printf("[ABC] Unregistered device %s from devsel %u\n",
+			   dev->name, old_devsel);
+	    }
+	} else {
+	    if (devsel < DEVSEL_NONE) {
+		con_printf("[ABC] Registered device %s on devsel %u\n",
+			   dev->name, devsel);
+	    } else {
+		con_printf("[ABC] Device %s is disabled\n", dev->name);
+	    }
+	}
+    }
 }
 
 void abc_init(void)

+ 4 - 0
rv32/abcio.h

@@ -45,6 +45,9 @@ struct abc_dev {
     abc_callback_t callback_out[6];
     abc_callback_t callback_inp[2];
     abc_callback_t callback_rst;
+
+    unsigned int devsel;
+    const char *name;
 };
 
 extern struct abc_dev *_abc_selected_dev;
@@ -94,6 +97,7 @@ void abc_register(struct abc_dev *dev, unsigned int devsel);
 void abc_init(void);
 
 void abcdisk_init(void);
+void abcdisk_config(void);
 void abcdisk_io_poll(void);
 
 void abc_init_memmap(void);

+ 7 - 4
rv32/abcpun80.c

@@ -8,8 +8,7 @@
 #include "common.h"
 #include "io.h"
 #include "abcio.h"
-
-#define PUN_IOSEL	60
+#include "config.h"
 
 /* ACM channel */
 #define PUN_TTY_CHAN	1
@@ -92,7 +91,8 @@ static struct abc_dev pun80_iodev = {
     .status_first_out_mask	= ~0,
     .status_first_inp_mask	= ~0,
     .callback_out[0]		= pun80_callback_out,
-    .callback_inp[0]		= pun80_callback_inp
+    .callback_inp[0]		= pun80_callback_inp,
+    .name                       = "pun80"
 };
 
 void pun80_init(void)
@@ -124,5 +124,8 @@ void pun80_init(void)
     PUN_IRQEN  = PUN_IRQ_MASK;
     unmask_irq(PUN_IRQ);
 
-    abc_register(&pun80_iodev, PUN_IOSEL);
+    unsigned int devsel = getvar_uint(config_abc_io_pun80_devsel);
+    if (!getvar_bool(config_abc_io_pun80_enable))
+	devsel = DEVSEL_NONE;
+    abc_register(&pun80_iodev, devsel);
 }

+ 7 - 3
rv32/abcrtc.c

@@ -10,8 +10,8 @@
 #include "abcio.h"
 #include "systime.h"
 #include "console.h"
+#include "config.h"
 
-#define RTC_DEVSEL 54
 #define RTC_CALLBACK_MASK ((1 << 8)|(1 << 2)|(1 << 0))
 
 #define RTC_MAGIC 211
@@ -103,10 +103,14 @@ static struct abc_dev rtc_iodev = {
     .inp_data[1] = RTC_READY|RTC_ID,
     .callback_out[0] = rtc_do_program_ready,
     .callback_out[2] = rtc_do_command,
-    .callback_inp[0] = rtc_do_id
+    .callback_inp[0] = rtc_do_id,
+    .name = "rtc"
 };
 
 void rtc_abc_init(void)
 {
-    abc_register(&rtc_iodev, RTC_DEVSEL);
+    unsigned int devsel = getvar_uint(config_abc_io_rtc_devsel);
+    if (!getvar_bool(config_abc_io_rtc_enable))
+	devsel = DEVSEL_NONE;
+    abc_register(&rtc_iodev, devsel);
 }

+ 1 - 1
rv32/checksum.h

@@ -1,4 +1,4 @@
 #ifndef CHECKSUM_H
 #define CHECKSUM_H
-#define SDRAM_SUM 0x9c38c8ce
+#define SDRAM_SUM 0xf231d760
 #endif

+ 10 - 2
rv32/config.c

@@ -3,7 +3,7 @@
 #include "console.h"
 #include "io.h"
 
-char config_buf[CONFIG_BUFSIZE];
+char __dram_bss config_buf[CONFIG_BUFSIZE];
 volatile bool do_update_config;
 bool _configured;
 
@@ -11,11 +11,19 @@ void update_config(void)
 {
     do_update_config = false;
 
-    memcpy(sysvar_val, config_buf, (size_t)sysvar_count * sizeof *sysvar_val);
+    memcpy(sysvar_val, config_buf, sizeof sysvar_val);
+    memset(sysvar_isset, 1, sizeof sysvar_isset);
 
     con_puts("[ESP] Configuration received: ");
     con_puts(_configured ? "update\n" : "initial\n");
 
+    for (enum sysvar_enum i = sysvar_null+1; i < sysvar_count; i++) {
+	con_puts(sysvar_name[i]);
+	con_putc('=');
+	con_puts(notempty(getvar_tostr(i)));
+	con_putc('\n');
+    }
+
     if (!_configured) {
 	_configured = true;
 	return;

+ 0 - 2
rv32/esp.c

@@ -17,8 +17,6 @@ IRQHANDLER(esp,0)
     uint32_t irqstatus = ESP_CPU_IRQ;
     ESP_CPU_IRQ_CLR = irqstatus;
 
-    con_printf("[ESP] ESP link IRQ, status = %08x\n", irqstatus);
-
     if (irqstatus & (1 << EL_DIRQ_UNDERRUN)) {
 	con_printf("[ESP] ESP link memory underrun!!\n");
 	ESP_SPI_IRQ = (1 << EL_UIRQ_READY); /* Block writes, reinitialize! */

+ 16 - 16
rv32/system.c

@@ -213,22 +213,6 @@ static void __noinline late_init(void)
 
     set_leds(4);
 
-    read_rtc();
-    rtc_abc_init();
-
-    set_leds(3);
-
-    sdcard_reset();
-    abcdisk_init();
-
-    set_leds(2);
-
-    pun80_init();
-
-    set_leds(1);
-
-    abc_init();
-
     esp_init();    /* Ready for communications */
 
     /* Let ESP know we are ready... */
@@ -243,6 +227,22 @@ static void __noinline late_init(void)
     }
     update_config();
 
+    set_leds(3);
+
+    read_rtc();
+    rtc_abc_init();
+
+    set_leds(2);
+
+    sdcard_reset();
+    abcdisk_init();
+
+    pun80_init();
+
+    set_leds(1);
+
+    abc_init();
+
     /* Release WAIT# if asserted */
     ABC_BUSCTL = 0;