Merge branch 'main' of github.com:rdolbeau/SBusFPGA into main
This commit is contained in:
commit
0b3cd1bfb5
4
NetBSD/9.0/etc/disktab.sbusfpga
Normal file
4
NetBSD/9.0/etc/disktab.sbusfpga
Normal file
@ -0,0 +1,4 @@
|
||||
sbusfpga256|SBusFPGA with 256 MiB SDRAM: \
|
||||
:ns#2:nt#4:nc#65536:se#512: \
|
||||
:oa#0:pa#524288:ta=4.2BSD: \
|
||||
:oc#0:pc#524288:
|
||||
13
NetBSD/9.0/etc/rc.d/sbusfpga_sdram
Normal file
13
NetBSD/9.0/etc/rc.d/sbusfpga_sdram
Normal file
@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# $NetBSD$
|
||||
#
|
||||
|
||||
# PROVIDE: SBUSFPGA_SDRAM
|
||||
|
||||
if test -b /dev/sbusfpga_sdram0; then
|
||||
for DEVICE in /dev/sbusfpga_sdram[0-9]; do
|
||||
test -b ${DEVICE} && disklabel -w ${DEVICE} sbusfpga256 || return
|
||||
test -b ${DEVICE}a && newfs ${DEVICE}a || return
|
||||
done
|
||||
fi
|
||||
197
NetBSD/9.0/usr/src/sys/dev/sbus/ohci_sbus.c
Normal file
197
NetBSD/9.0/usr/src/sys/dev/sbus/ohci_sbus.c
Normal file
@ -0,0 +1,197 @@
|
||||
/* $NetBSD$ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998, 2021 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Lennart Augustsson (lennart@augustsson.net) at
|
||||
* Carlstedt Research & Technology.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/device.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <sys/bus.h>
|
||||
|
||||
#include <dev/sbus/sbusvar.h>
|
||||
#include <machine/autoconf.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
#include <dev/usb/usbdi.h>
|
||||
#include <dev/usb/usbdivar.h>
|
||||
#include <dev/usb/usb_mem.h>
|
||||
|
||||
#include <dev/usb/ohcireg.h>
|
||||
#include <dev/usb/ohcivar.h>
|
||||
|
||||
struct ohci_sbus_softc {
|
||||
ohci_softc_t sc;
|
||||
void *sc_ih;
|
||||
int sc_node;
|
||||
int sc_burst;
|
||||
};
|
||||
|
||||
static int
|
||||
ohci_sbus_match(device_t parent, cfdata_t match, void *aux)
|
||||
{
|
||||
struct sbus_attach_args *sa = (struct sbus_attach_args *)aux;
|
||||
/* generic-ohci is the default name, from device-tree */
|
||||
if (strcmp("generic-ohci", sa->sa_name) == 0)
|
||||
return 1;
|
||||
/* usb is the OFW name, qualified by device-type */
|
||||
const char* type = prom_getpropstring(sa->sa_node, "device-type");
|
||||
if (type != NULL && (strcmp("ohci", type) == 0))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ohci_sbus_attach(device_t parent, device_t self, void *aux)
|
||||
{
|
||||
struct ohci_sbus_softc *sc = device_private(self);
|
||||
struct sbus_attach_args *sa = (struct sbus_attach_args *)aux;
|
||||
struct sbus_softc *sbsc = device_private(parent);
|
||||
int sbusburst;
|
||||
|
||||
sc->sc.sc_dev = self;
|
||||
sc->sc.sc_bus.ub_hcpriv = sc;
|
||||
sc->sc.iot = sa->sa_bustag;
|
||||
sc->sc.sc_size = sa->sa_size;
|
||||
|
||||
/* **** SBus specific */
|
||||
sc->sc_node = sa->sa_node;
|
||||
/*
|
||||
* Get transfer burst size from PROM
|
||||
*/
|
||||
sbusburst = sbsc->sc_burst;
|
||||
if (sbusburst == 0)
|
||||
sbusburst = SBUS_BURST_32 - 1; /* 1->16 */
|
||||
sc->sc_burst = prom_getpropint(sc->sc_node, "burst-sizes", -1);
|
||||
if (sc->sc_burst == -1)
|
||||
/* take SBus burst sizes */
|
||||
sc->sc_burst = sbusburst;
|
||||
/* Clamp at parent's burst sizes */
|
||||
sc->sc_burst &= sbusburst;
|
||||
|
||||
if (0) { /* in PCI there's a test for some specific controller */
|
||||
sc->sc.sc_flags = OHCIF_SUPERIO;
|
||||
}
|
||||
|
||||
/* check if memory space access is enabled */
|
||||
/* CHECKME: not needed ? */
|
||||
|
||||
/* Map I/O registers */
|
||||
if (sbus_bus_map(sc->sc.iot, sa->sa_slot, sa->sa_offset, sc->sc.sc_size,
|
||||
BUS_SPACE_MAP_LINEAR, &sc->sc.ioh) != 0) {
|
||||
aprint_error_dev(self, ": cannot map registers\n");
|
||||
return;
|
||||
}
|
||||
|
||||
aprint_normal_dev(self, "nid 0x%x, bustag %p (0x%zx @ 0x%08lx), burst 0x%x (parent 0x%0x)\n",
|
||||
sc->sc_node,
|
||||
sc->sc.iot,
|
||||
(size_t)sc->sc.sc_size,
|
||||
sc->sc.ioh,
|
||||
sc->sc_burst,
|
||||
sbsc->sc_burst);
|
||||
|
||||
/* we're SPECIAL!!! */
|
||||
/* sc->sc.sc_endian = OHCI_BIG_ENDIAN; */
|
||||
|
||||
/* Disable interrupts, so we don't get any spurious ones. */
|
||||
bus_space_write_4(sc->sc.iot, sc->sc.ioh, OHCI_INTERRUPT_DISABLE,
|
||||
OHCI_ALL_INTRS);
|
||||
|
||||
sc->sc.sc_bus.ub_dmatag = sa->sa_dmatag;
|
||||
/* sc->sc.sc_bus.ub_dmatag = (void*)((char*)sc->sc.ioh + 0x10000); */
|
||||
|
||||
/* Enable the device. */
|
||||
/* CHECKME: not needed ? */
|
||||
|
||||
/* Map and establish the interrupt. */
|
||||
if (sa->sa_nintr != 0) {
|
||||
sc->sc_ih = bus_intr_establish(sc->sc.iot, sa->sa_pri,
|
||||
IPL_NET, ohci_intr, sc); // checkme: interrupt priority
|
||||
if (sc->sc_ih == NULL) {
|
||||
aprint_error_dev(self, "couldn't establish interrupt (%d)\n", sa->sa_nintr);
|
||||
} else
|
||||
aprint_normal_dev(self, "interrupting at %d / %d / %d\n", sa->sa_nintr, sa->sa_pri, IPL_NET);
|
||||
} else {
|
||||
aprint_error_dev(self, "no interrupt defined in PROM\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
int err = ohci_init(&sc->sc);
|
||||
if (err) {
|
||||
aprint_error_dev(self, "init failed, error=%d\n", err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!pmf_device_register1(self, ohci_suspend, ohci_resume,
|
||||
ohci_shutdown))
|
||||
aprint_error_dev(self, "couldn't establish power handler\n");
|
||||
|
||||
/* Attach usb device. */
|
||||
sc->sc.sc_child = config_found(self, &sc->sc.sc_bus, usbctlprint);
|
||||
return;
|
||||
|
||||
fail:
|
||||
/* should we unmap ? */
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
ohci_sbus_detach(device_t self, int flags)
|
||||
{
|
||||
struct ohci_sbus_softc *sc = device_private(self);
|
||||
int rv;
|
||||
|
||||
rv = ohci_detach(&sc->sc, flags);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
pmf_device_deregister(self);
|
||||
|
||||
ohci_shutdown(self, flags);
|
||||
|
||||
/* Disable interrupts, so we don't get any spurious ones. */
|
||||
bus_space_write_4(sc->sc.iot, sc->sc.ioh,
|
||||
OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS);
|
||||
|
||||
/* can we disestablish the interrupt ? */
|
||||
/* can we unmap the registers ? */
|
||||
return 0;
|
||||
}
|
||||
|
||||
CFATTACH_DECL3_NEW(ohci_sbus, sizeof(struct ohci_sbus_softc),
|
||||
ohci_sbus_match, ohci_sbus_attach, ohci_sbus_detach, ohci_activate, NULL,
|
||||
ohci_childdet, DVF_DETACH_SHUTDOWN);
|
||||
@ -112,7 +112,7 @@ extern struct cfdriver rdfpga_sdcard_cd;
|
||||
|
||||
static int rdfpga_sdcard_wait_dma_ready(struct rdfpga_sdcard_softc *sc, const int count);
|
||||
static int rdfpga_sdcard_wait_device_ready(struct rdfpga_sdcard_softc *sc, const int count);
|
||||
static int rdfpga_sdcard_read_block(struct rdfpga_sdcard_softc *sc, const u_int32_t block, void *data);
|
||||
static int rdfpga_sdcard_read_block(struct rdfpga_sdcard_softc *sc, const u_int32_t block, const u_int32_t blkcnt, void *data);
|
||||
static int rdfpga_sdcard_write_block(struct rdfpga_sdcard_softc *sc, const u_int32_t block, void *data);
|
||||
|
||||
struct rdfpga_sdcard_rb_32to512 {
|
||||
@ -179,7 +179,7 @@ rdfpga_sdcard_ioctl (dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
|
||||
case RDFPGA_SDCARD_RB:
|
||||
{
|
||||
struct rdfpga_sdcard_rb_32to512* u = data;
|
||||
err = rdfpga_sdcard_read_block(sc, u->block, u->data);
|
||||
err = rdfpga_sdcard_read_block(sc, u->block, 1, u->data);
|
||||
break;
|
||||
}
|
||||
case RDFPGA_SDCARD_WB:
|
||||
@ -188,49 +188,6 @@ rdfpga_sdcard_ioctl (dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
|
||||
err = rdfpga_sdcard_write_block(sc, u->block, u->data);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
case DIOCGDINFO:
|
||||
*(struct disklabel *)data = *(sc->dk.sc_dkdev.dk_label);
|
||||
break;
|
||||
|
||||
case DIOCGDEFLABEL:
|
||||
{
|
||||
struct disklabel *lp = sc->dk.sc_dkdev.dk_label;
|
||||
struct cpu_disklabel *clp = sc->dk.sc_dkdev.dk_cpulabel;
|
||||
memset(lp, 0, sizeof(struct disklabel));
|
||||
memset(clp, 0, sizeof(struct cpu_disklabel));
|
||||
if (readdisklabel(dev, rdfpga_sdcard_strategy, lp, clp) != NULL) {
|
||||
int i;
|
||||
aprint_normal_dev(sc->dk.sc_dev, "read disk label OK\n");
|
||||
strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
|
||||
/*
|
||||
* Reset the partition info; it might have gotten
|
||||
* trashed in readdisklabel().
|
||||
*
|
||||
* XXX Why do we have to do this? readdisklabel()
|
||||
* should be safe...
|
||||
*/
|
||||
for (i = 0; i < MAXPARTITIONS; ++i) {
|
||||
lp->d_partitions[i].p_offset = 0;
|
||||
if (i == RAW_PART) {
|
||||
lp->d_partitions[i].p_size =
|
||||
lp->d_secpercyl * lp->d_ncylinders;
|
||||
lp->d_partitions[i].p_fstype = FS_BSDFFS;
|
||||
} else {
|
||||
lp->d_partitions[i].p_size = 0;
|
||||
lp->d_partitions[i].p_fstype = FS_UNUSED;
|
||||
}
|
||||
}
|
||||
lp->d_npartitions = RAW_PART + 1;
|
||||
memcpy(data, lp, sizeof(struct disklabel));
|
||||
} else {
|
||||
aprint_normal_dev(sc->dk.sc_dev, "read disk label FAILED\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
/* case VNDIOCCLR: */
|
||||
/* case VNDIOCCLR50: */
|
||||
@ -505,9 +462,10 @@ static int rdfpga_sdcard_wait_device_ready(struct rdfpga_sdcard_softc *sc, const
|
||||
return rdfpga_sdcard_wait_dma_ready(sc, count);
|
||||
}
|
||||
|
||||
static int rdfpga_sdcard_read_block(struct rdfpga_sdcard_softc *sc, const u_int32_t block, void *data) {
|
||||
static int rdfpga_sdcard_read_block(struct rdfpga_sdcard_softc *sc, const u_int32_t block, const u_int32_t blkcnt, void *data) {
|
||||
int res = 0;
|
||||
u_int32_t ctrl;
|
||||
u_int32_t ctrl = 0;
|
||||
u_int32_t idx = 0;
|
||||
/* aprint_normal_dev(sc->dk.sc_dev, "Reading block %u from sdcard\n", block); */
|
||||
|
||||
if ((res = rdfpga_sdcard_wait_device_ready(sc, 50000)) != 0)
|
||||
@ -524,9 +482,6 @@ static int rdfpga_sdcard_read_block(struct rdfpga_sdcard_softc *sc, const u_int3
|
||||
bus_dmamem_free(sc->sc_dmatag, &sc->sc_segs, 1);
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
/* for testing only, remove */
|
||||
//memcpy(kvap, data, 512);
|
||||
|
||||
if (bus_dmamap_load(sc->sc_dmatag, sc->sc_dmamap, kvap, RDFPGA_SDCARD_VAL_DMA_MAX_SZ, /* kernel space */ NULL,
|
||||
BUS_DMA_NOWAIT | BUS_DMA_STREAMING | BUS_DMA_WRITE)) {
|
||||
@ -536,24 +491,28 @@ static int rdfpga_sdcard_read_block(struct rdfpga_sdcard_softc *sc, const u_int3
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, 0, 512, BUS_DMASYNC_PREWRITE);
|
||||
bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, 0, blkcnt * 512, BUS_DMASYNC_PREWRITE);
|
||||
|
||||
/* set DMA address */
|
||||
bus_space_write_4(sc->sc_bustag, sc->sc_bhregs, RDFPGA_SDCARD_REG_DMAW_ADDR, (uint32_t)(sc->sc_dmamap->dm_segs[0].ds_addr));
|
||||
/* set block to read */
|
||||
bus_space_write_4(sc->sc_bustag, sc->sc_bhregs, RDFPGA_SDCARD_REG_ADDR, block);
|
||||
ctrl = RDFPGA_SDCARD_CTRL_START | RDFPGA_SDCARD_CTRL_READ;
|
||||
/* initiate reading block from SDcard; once the read request is acknowledged, the HW will start the DMA engine */
|
||||
bus_space_write_4(sc->sc_bustag, sc->sc_bhregs, RDFPGA_SDCARD_REG_CTRL, ctrl);
|
||||
for (idx = 0 ; idx < blkcnt && !res; idx++) {
|
||||
bus_addr_t addr = sc->sc_dmamap->dm_segs[0].ds_addr + 512 * idx;
|
||||
|
||||
/* set DMA address */
|
||||
bus_space_write_4(sc->sc_bustag, sc->sc_bhregs, RDFPGA_SDCARD_REG_DMAW_ADDR, (uint32_t)(addr));
|
||||
/* set block to read */
|
||||
bus_space_write_4(sc->sc_bustag, sc->sc_bhregs, RDFPGA_SDCARD_REG_ADDR, (block + idx));
|
||||
ctrl = RDFPGA_SDCARD_CTRL_START | RDFPGA_SDCARD_CTRL_READ;
|
||||
/* initiate reading block from SDcard; once the read request is acknowledged, the HW will start the DMA engine */
|
||||
bus_space_write_4(sc->sc_bustag, sc->sc_bhregs, RDFPGA_SDCARD_REG_CTRL, ctrl);
|
||||
|
||||
res = rdfpga_sdcard_wait_device_ready(sc, 100000);
|
||||
}
|
||||
|
||||
res = rdfpga_sdcard_wait_device_ready(sc, 100000);
|
||||
|
||||
bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, 0, 512, BUS_DMASYNC_POSTWRITE);
|
||||
bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, 0, blkcnt * 512, BUS_DMASYNC_POSTWRITE);
|
||||
|
||||
bus_dmamap_unload(sc->sc_dmatag, sc->sc_dmamap);
|
||||
/* aprint_normal_dev(sc->dk.sc_dev, "dma: unloaded\n"); */
|
||||
|
||||
memcpy(data, kvap, 512);
|
||||
memcpy(data, kvap, blkcnt * 512);
|
||||
|
||||
bus_dmamem_unmap(sc->sc_dmatag, kvap, RDFPGA_SDCARD_VAL_DMA_MAX_SZ);
|
||||
/* aprint_normal_dev(sc->dk.sc_dev, "dma: unmapped\n"); */
|
||||
@ -625,100 +584,9 @@ static int rdfpga_sdcard_write_block(struct rdfpga_sdcard_softc *sc, const u_int
|
||||
void
|
||||
rdfpga_sdcard_strategy(struct buf *bp)
|
||||
{
|
||||
#if 0
|
||||
struct rdfpga_sdcard_softc *sc = device_lookup_private(&rdfpga_sdcard_cd, DISKUNIT(bp->b_dev));
|
||||
int err = 0;
|
||||
if (sc == NULL) {
|
||||
aprint_error("%s:%d: sc == NULL! giving up\n", __PRETTY_FUNCTION__, __LINE__);
|
||||
bp->b_resid = bp->b_bcount;
|
||||
bp->b_error = EINVAL;
|
||||
goto done;
|
||||
}
|
||||
/* aprint_normal_dev(sc->dk.sc_dev, "%s:%d: bp->b_bflags = 0x%08x\n", __PRETTY_FUNCTION__, __LINE__, bp->b_flags); */
|
||||
/* aprint_normal_dev(sc->dk.sc_dev, "%s:%d: bp->b_bufsize = %d\n", __PRETTY_FUNCTION__, __LINE__, bp->b_bufsize); */
|
||||
/* aprint_normal_dev(sc->dk.sc_dev, "%s:%d: bp->b_blkno = %lld\n", __PRETTY_FUNCTION__, __LINE__, bp->b_blkno); */
|
||||
/* aprint_normal_dev(sc->dk.sc_dev, "%s:%d: bp->b_rawblkno = %lld\n", __PRETTY_FUNCTION__, __LINE__, bp->b_rawblkno); */
|
||||
/* aprint_normal_dev(sc->dk.sc_dev, "%s:%d: bp->b_bcount = %d\n", __PRETTY_FUNCTION__, __LINE__, bp->b_bcount); */
|
||||
|
||||
bp->b_resid = bp->b_bcount;
|
||||
|
||||
if (bp->b_bcount == 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (bp->b_flags & B_READ) {
|
||||
unsigned char* data = bp->b_data;
|
||||
daddr_t blk = bp->b_blkno;
|
||||
struct partition *p = NULL;
|
||||
|
||||
if (DISKPART(bp->b_dev) != RAW_PART) {
|
||||
if ((err = bounds_check_with_label(&sc->dk.sc_dkdev, bp, 0)) <= 0) {
|
||||
aprint_error("%s:%d: bounds_check_with_label -> %d\n", __PRETTY_FUNCTION__, __LINE__, err);
|
||||
bp->b_resid = bp->b_bcount;
|
||||
goto done;
|
||||
}
|
||||
p = &sc->dk.sc_dkdev.dk_label->d_partitions[DISKPART(bp->b_dev)];
|
||||
blk = bp->b_blkno + p->p_offset;
|
||||
}
|
||||
|
||||
while (bp->b_resid >= 512 && !bp->b_error) {
|
||||
if (blk < 62521344) {
|
||||
aprint_normal_dev(sc->dk.sc_dev, "%s:%d: bp->b_blkno = %lld, computed %lld (part %d)\n", __PRETTY_FUNCTION__, __LINE__, bp->b_blkno, blk, DISKPART(bp->b_dev));
|
||||
aprint_normal_dev(sc->dk.sc_dev, "%s:%d: bp->b_rawblkno = %lld\n", __PRETTY_FUNCTION__, __LINE__, bp->b_rawblkno);
|
||||
bp->b_error = rdfpga_sdcard_read_block(sc, blk, data);
|
||||
} else {
|
||||
aprint_error("%s:%d: blk = %lld read out of range! giving up\n", __PRETTY_FUNCTION__, __LINE__, blk);
|
||||
bp->b_error = EINVAL;
|
||||
}
|
||||
blk ++;
|
||||
data += 512;
|
||||
bp->b_resid -= 512;
|
||||
}
|
||||
} else {
|
||||
#if 1
|
||||
bp->b_error = EINVAL;
|
||||
aprint_normal_dev(sc->dk.sc_dev, "%s:%d: bp->b_bflags = 0x%08x\n", __PRETTY_FUNCTION__, __LINE__, bp->b_flags);
|
||||
aprint_normal_dev(sc->dk.sc_dev, "%s:%d: bp->b_bufsize = %d\n", __PRETTY_FUNCTION__, __LINE__, bp->b_bufsize);
|
||||
aprint_normal_dev(sc->dk.sc_dev, "%s:%d: bp->b_blkno = %lld\n", __PRETTY_FUNCTION__, __LINE__, bp->b_blkno);
|
||||
aprint_normal_dev(sc->dk.sc_dev, "%s:%d: bp->b_rawblkno = %lld\n", __PRETTY_FUNCTION__, __LINE__, bp->b_rawblkno);
|
||||
aprint_normal_dev(sc->dk.sc_dev, "%s:%d: bp->b_bcount = %d\n", __PRETTY_FUNCTION__, __LINE__, bp->b_bcount);
|
||||
#else
|
||||
unsigned char* data = bp->b_data;
|
||||
daddr_t blk = bp->b_blkno;
|
||||
|
||||
if (DISKPART(bp->b_dev) != RAW_PART) {
|
||||
if (bounds_check_with_label(&sc->dk.sc_dkdev, bp, 0) <= 0) {
|
||||
bp->b_resid = bp->b_bcount;
|
||||
goto done;
|
||||
}
|
||||
p = &sc->dk.sc_dkdev.dk_label->d_partitions[DISKPART(bp->b_dev)];
|
||||
blk = bp->b_blkno + p->p_offset;
|
||||
}
|
||||
|
||||
while (bp->b_resid >= 512 && !bp->b_error) {
|
||||
if (blk < 62521344) {
|
||||
bp->b_error = rdfpga_sdcard_write_block(sc, blk, data);
|
||||
} else {
|
||||
aprint_error("%s:%d: blk = %lld write out of range! giving up\n", __PRETTY_FUNCTION__, __LINE__, blk);
|
||||
bp->b_error = EINVAL;
|
||||
}
|
||||
blk ++;
|
||||
data += 512;
|
||||
bp->b_resid -= 512;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* aprint_normal_dev(sc->dk.sc_dev, "%s:%d: bp->b_resid = %d\n", __PRETTY_FUNCTION__, __LINE__, bp->b_resid); */
|
||||
/* aprint_normal_dev(sc->dk.sc_dev, "%s:%d: bp->b_error = %d\n", __PRETTY_FUNCTION__, __LINE__, bp->b_error); */
|
||||
|
||||
done:
|
||||
biodone(bp);
|
||||
#else
|
||||
struct rdfpga_sdcard_softc *sc = device_lookup_private(&rdfpga_sdcard_cd, DISKUNIT(bp->b_dev));
|
||||
|
||||
dk_strategy(&sc->dk, bp);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void rdfpga_sdcard_set_geometry(struct rdfpga_sdcard_softc *sc) {
|
||||
@ -749,8 +617,8 @@ rdfpga_sdcard_size(dev_t dev) {
|
||||
static void
|
||||
rdfpga_sdcard_minphys(struct buf *bp)
|
||||
{
|
||||
if (bp->b_bcount > 16)
|
||||
bp->b_bcount = 16;
|
||||
if (bp->b_bcount > RDFPGA_SDCARD_VAL_DMA_MAX_SZ)
|
||||
bp->b_bcount = RDFPGA_SDCARD_VAL_DMA_MAX_SZ;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -792,15 +660,20 @@ rdfpga_sdcard_diskstart(device_t self, struct buf *bp)
|
||||
/* } */
|
||||
|
||||
while (bp->b_resid >= 512 && !err) {
|
||||
if (blk < 62521344) {
|
||||
err = rdfpga_sdcard_read_block(sc, blk, data);
|
||||
u_int32_t blkcnt = bp->b_resid / 512;
|
||||
|
||||
if (blkcnt > (RDFPGA_SDCARD_VAL_DMA_MAX_SZ/512))
|
||||
blkcnt = (RDFPGA_SDCARD_VAL_DMA_MAX_SZ/512);
|
||||
|
||||
if (blk+blkcnt <= 62521344) {
|
||||
err = rdfpga_sdcard_read_block(sc, blk, blkcnt, data);
|
||||
} else {
|
||||
aprint_error("%s:%d: blk = %lld read out of range! giving up\n", __PRETTY_FUNCTION__, __LINE__, blk);
|
||||
err = EINVAL;
|
||||
}
|
||||
blk ++;
|
||||
data += 512;
|
||||
bp->b_resid -= 512;
|
||||
blk += blkcnt;
|
||||
data += 512 * blkcnt;
|
||||
bp->b_resid -= 512 * blkcnt;
|
||||
}
|
||||
} else {
|
||||
#if 1
|
||||
|
||||
@ -66,7 +66,7 @@ struct rdfpga_sdcard_softc {
|
||||
#define RDFPGA_SDCARD_CTRL_START 0x80000000
|
||||
#define RDFPGA_SDCARD_CTRL_READ 0x40000000
|
||||
|
||||
/* one page, though we're likely to only use 512 bytes (one block) ATM */
|
||||
#define RDFPGA_SDCARD_VAL_DMA_MAX_SZ (4096)
|
||||
/* 16 pages, though we're likely to only use 512 bytes (one block) ATM */
|
||||
#define RDFPGA_SDCARD_VAL_DMA_MAX_SZ (65536)
|
||||
|
||||
#endif /* _RDFPGA_SDCARD_H_ */
|
||||
|
||||
1070
NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_curve25519engine.c
Normal file
1070
NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_curve25519engine.c
Normal file
File diff suppressed because it is too large
Load Diff
62
NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_curve25519engine.h
Normal file
62
NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_curve25519engine.h
Normal file
@ -0,0 +1,62 @@
|
||||
/* $NetBSD$ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2020 Romain Dolbeau <romain@dolbeau.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _SBUSFPGA_CURVE25519ENGINE_H_
|
||||
#define _SBUSFPGA_CURVE25519ENGINE_H_
|
||||
|
||||
#define MAX_SESSION 32 // HW limit
|
||||
#define MAX_ACTIVE_SESSION 8 // SW-imposed limit
|
||||
// Single 4KiB pages per session
|
||||
#define SBUSFPGA_CURVE25519ENGINE_VAL_DMA_MAX_SZ (MAX_ACTIVE_SESSION*4*1024)
|
||||
|
||||
struct sbusfpga_curve25519engine_softc {
|
||||
device_t sc_dev; /* us as a device */
|
||||
u_int sc_rev; /* revision */
|
||||
int sc_node; /* PROM node ID */
|
||||
int sc_burst; /* DVMA burst size in effect */
|
||||
bus_space_tag_t sc_bustag; /* bus tag */
|
||||
bus_space_handle_t sc_bhregs_curve25519engine; /* bus handle */
|
||||
bus_space_handle_t sc_bhregs_microcode; /* bus handle */
|
||||
bus_space_handle_t sc_bhregs_regfile; /* bus handle */
|
||||
//void * sc_buffer; /* VA of the registers */
|
||||
int sc_bufsiz_curve25519engine; /* Size of buffer */
|
||||
int sc_bufsiz_microcode; /* Size of buffer */
|
||||
int sc_bufsiz_regfile; /* Size of buffer */
|
||||
int initialized;
|
||||
uint32_t active_sessions;
|
||||
uint32_t mapped_sessions;
|
||||
uint32_t sessions_cookies[MAX_ACTIVE_SESSION];
|
||||
/* DMA kernel structures */
|
||||
bus_dma_tag_t sc_dmatag;
|
||||
bus_dmamap_t sc_dmamap;
|
||||
bus_dma_segment_t sc_segs;
|
||||
int sc_rsegs;
|
||||
void * sc_dma_kva;
|
||||
};
|
||||
|
||||
#endif /* _SBUSFPGA_CURVE25519ENGINE_H_ */
|
||||
1898
NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_sdram.c
Normal file
1898
NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_sdram.c
Normal file
File diff suppressed because it is too large
Load Diff
62
NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_sdram.h
Normal file
62
NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_sdram.h
Normal file
@ -0,0 +1,62 @@
|
||||
/* $NetBSD$ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2020 Romain Dolbeau <romain@dolbeau.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _SBUSFPGA_SDRAM_H_
|
||||
#define _SBUSFPGA_SDRAM_H_
|
||||
|
||||
struct sbusfpga_sdram_softc {
|
||||
struct dk_softc dk;
|
||||
/* device_t sc_dev; */ /* us as a device */ /* in dk */
|
||||
u_int sc_rev; /* revision */
|
||||
int sc_node; /* PROM node ID */
|
||||
int sc_burst; /* DVMA burst size in effect */
|
||||
bus_space_tag_t sc_bustag; /* bus tag */
|
||||
bus_space_handle_t sc_bhregs_ddrphy; /* bus handle */
|
||||
bus_space_handle_t sc_bhregs_sdram; /* bus handle */
|
||||
bus_space_handle_t sc_bhregs_exchange_with_mem; /* bus handle */
|
||||
bus_space_handle_t sc_bhregs_mmap; /* bus handle */
|
||||
int sc_bufsiz_ddrphy; /* Size of buffer */
|
||||
int sc_bufsiz_sdram; /* Size of buffer */
|
||||
int sc_bufsiz_exchange_with_mem; /* bus handle */
|
||||
int sc_bufsiz_mmap; /* bus handle */
|
||||
/* specific of the DMA engine */
|
||||
u_int dma_blk_size;
|
||||
u_int dma_blk_base;
|
||||
u_int dma_mem_size; /* in blk_size */
|
||||
u_int dma_real_mem_size; /* precomputed in bytes */
|
||||
/* DMA kernel structures */
|
||||
bus_dma_tag_t sc_dmatag;
|
||||
bus_dmamap_t sc_dmamap;
|
||||
bus_dma_segment_t sc_segs;
|
||||
int sc_rsegs;
|
||||
void * sc_dma_kva;
|
||||
};
|
||||
|
||||
#define SBUSFPGA_SDRAM_VAL_DMA_MAX_SZ (64*1024)
|
||||
|
||||
#endif /* _SBUSFPGA_SDRAM_H_ */
|
||||
257
NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_stat.c
Normal file
257
NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_stat.c
Normal file
@ -0,0 +1,257 @@
|
||||
/* $NetBSD$ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2020 Romain Dolbeau <romain@dolbeau.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/device.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <sys/bus.h>
|
||||
#include <machine/autoconf.h>
|
||||
#include <sys/cpu.h>
|
||||
#include <sys/conf.h>
|
||||
|
||||
#include <sys/rndsource.h>
|
||||
|
||||
#include <dev/sbus/sbusvar.h>
|
||||
|
||||
#include <dev/sbus/sbusfpga_stat.h>
|
||||
|
||||
#include <machine/param.h>
|
||||
|
||||
int sbusfpga_stat_print(void *, const char *);
|
||||
int sbusfpga_stat_match(device_t, cfdata_t, void *);
|
||||
void sbusfpga_stat_attach(device_t, device_t, void *);
|
||||
|
||||
CFATTACH_DECL_NEW(sbusfpga_stat, sizeof(struct sbusfpga_sbus_bus_stat_softc),
|
||||
sbusfpga_stat_match, sbusfpga_stat_attach, NULL, NULL);
|
||||
|
||||
dev_type_open(sbusfpga_stat_open);
|
||||
dev_type_close(sbusfpga_stat_close);
|
||||
dev_type_ioctl(sbusfpga_stat_ioctl);
|
||||
|
||||
|
||||
const struct cdevsw sbusfpga_stat_cdevsw = {
|
||||
.d_open = sbusfpga_stat_open,
|
||||
.d_close = sbusfpga_stat_close,
|
||||
.d_read = noread,
|
||||
.d_write = nowrite,
|
||||
.d_ioctl = sbusfpga_stat_ioctl,
|
||||
.d_stop = nostop,
|
||||
.d_tty = notty,
|
||||
.d_poll = nopoll,
|
||||
.d_mmap = nommap,
|
||||
.d_kqfilter = nokqfilter,
|
||||
.d_discard = nodiscard,
|
||||
.d_flag = 0
|
||||
};
|
||||
|
||||
extern struct cfdriver sbusfpga_stat_cd;
|
||||
int
|
||||
sbusfpga_stat_open(dev_t dev, int flags, int mode, struct lwp *l)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
sbusfpga_stat_close(dev_t dev, int flags, int mode, struct lwp *l)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
sbusfpga_stat_print(void *aux, const char *busname)
|
||||
{
|
||||
|
||||
sbus_print(aux, busname);
|
||||
return (UNCONF);
|
||||
}
|
||||
|
||||
int
|
||||
sbusfpga_stat_match(device_t parent, cfdata_t cf, void *aux)
|
||||
{
|
||||
struct sbus_attach_args *sa = (struct sbus_attach_args *)aux;
|
||||
|
||||
return (strcmp("RDOL,sbusstat", sa->sa_name) == 0);
|
||||
}
|
||||
|
||||
#define CONFIG_CSR_DATA_WIDTH 32
|
||||
// define CSR_LEDS_BASE & others to avoid defining the CSRs of HW we don't handle
|
||||
#define CSR_LEDS_BASE
|
||||
#define CSR_CURVE25519ENGINE_BASE
|
||||
#define CSR_DDRPHY_BASE
|
||||
#define CSR_EXCHANGE_WITH_MEM_BASE
|
||||
// #define CSR_SBUS_BUS_STAT_BASE
|
||||
#define CSR_SDRAM_BASE
|
||||
#define CSR_SDBLOCK2MEM_BASE
|
||||
#define CSR_SDCORE_BASE
|
||||
#define CSR_SDIRQ_BASE
|
||||
#define CSR_SDMEM2BLOCK_BASE
|
||||
#define CSR_SDPHY_BASE
|
||||
#define CSR_TRNG_BASE
|
||||
#include "dev/sbus/litex_csr.h"
|
||||
#undef CSR_LEDS_BASE
|
||||
#undef CSR_CURVE25519ENGINE_BASE
|
||||
#undef CSR_DDRPHY_BASE
|
||||
#undef CSR_EXCHANGE_WITH_MEM_BASE
|
||||
// #undef CSR_SBUS_BUS_STAT_BASE
|
||||
#undef CSR_SDRAM_BASE
|
||||
#undef CSR_SDBLOCK2MEM_BASE
|
||||
#undef CSR_SDCORE_BASE
|
||||
#undef CSR_SDIRQ_BASE
|
||||
#undef CSR_SDMEM2BLOCK_BASE
|
||||
#undef CSR_SDPHY_BASE
|
||||
//#undef CSR_TRNG_BASE
|
||||
|
||||
|
||||
static void sbusfpga_stat_display(void *);
|
||||
|
||||
/*
|
||||
* Attach all the sub-devices we can find
|
||||
*/
|
||||
void
|
||||
sbusfpga_stat_attach(device_t parent, device_t self, void *aux)
|
||||
{
|
||||
struct sbus_attach_args *sa = aux;
|
||||
struct sbusfpga_sbus_bus_stat_softc *sc = device_private(self);
|
||||
struct sbus_softc *sbsc = device_private(parent);
|
||||
int node;
|
||||
int sbusburst;
|
||||
|
||||
sc->sc_bustag = sa->sa_bustag;
|
||||
sc->sc_dev = self;
|
||||
|
||||
if (sbus_bus_map(sc->sc_bustag, sa->sa_slot, sa->sa_offset, sa->sa_size,
|
||||
BUS_SPACE_MAP_LINEAR, &sc->sc_bhregs_sbus_bus_stat) != 0) {
|
||||
aprint_error(": cannot map registers\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sc->sc_bufsiz = sa->sa_size;
|
||||
|
||||
node = sc->sc_node = sa->sa_node;
|
||||
|
||||
/*
|
||||
* Get transfer burst size from PROM
|
||||
*/
|
||||
sbusburst = sbsc->sc_burst;
|
||||
if (sbusburst == 0)
|
||||
sbusburst = SBUS_BURST_32 - 1; /* 1->16 */
|
||||
|
||||
sc->sc_burst = prom_getpropint(node, "burst-sizes", -1);
|
||||
if (sc->sc_burst == -1)
|
||||
/* take SBus burst sizes */
|
||||
sc->sc_burst = sbusburst;
|
||||
|
||||
/* Clamp at parent's burst sizes */
|
||||
sc->sc_burst &= sbusburst;
|
||||
|
||||
aprint_normal("\n");
|
||||
aprint_normal_dev(self, "nid 0x%x, bustag %p, burst 0x%x (parent 0x%0x)\n",
|
||||
sc->sc_node,
|
||||
sc->sc_bustag,
|
||||
sc->sc_burst,
|
||||
sbsc->sc_burst);
|
||||
|
||||
sc->sc_delay = 5 * hz; // five seconds
|
||||
|
||||
callout_init(&sc->sc_display, CALLOUT_MPSAFE);
|
||||
callout_setfunc(&sc->sc_display, sbusfpga_stat_display, sc);
|
||||
/* disable by default */
|
||||
sc->sc_enable = 0;
|
||||
/* do it once during boot*/
|
||||
callout_schedule(&sc->sc_display, sc->sc_delay);
|
||||
}
|
||||
|
||||
#define SBUSFPGA_STAT_ON _IO(0, 1)
|
||||
#define SBUSFPGA_STAT_OFF _IO(0, 0)
|
||||
|
||||
int
|
||||
sbusfpga_stat_ioctl (dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
|
||||
{
|
||||
struct sbusfpga_sbus_bus_stat_softc *sc = device_lookup_private(&sbusfpga_stat_cd, minor(dev));
|
||||
int err = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case SBUSFPGA_STAT_ON:
|
||||
if (!sc->sc_enable) {
|
||||
sc->sc_enable = 1;
|
||||
callout_schedule(&sc->sc_display, sc->sc_delay);
|
||||
}
|
||||
break;
|
||||
case SBUSFPGA_STAT_OFF:
|
||||
if (sc->sc_enable) {
|
||||
callout_stop(&sc->sc_display);
|
||||
sc->sc_enable = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
err = ENOTTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void sbusfpga_stat_display(void *args) {
|
||||
struct sbusfpga_sbus_bus_stat_softc *sc = args;
|
||||
unsigned int c = sbus_bus_stat_stat_cycle_counter_read(sc), c2;
|
||||
int count;
|
||||
sbus_bus_stat_stat_ctrl_write(sc, 1);
|
||||
delay(1);
|
||||
count = 0;
|
||||
while (count < 10 && ((c2 = sbus_bus_stat_stat_cycle_counter_read(sc)) == c)) {
|
||||
count ++;
|
||||
delay(1);
|
||||
}
|
||||
if ((c2 == c) || (c2 == 0)){
|
||||
device_printf(sc->sc_dev, "Statistics didn't update\n");
|
||||
} else {
|
||||
device_printf(sc->sc_dev, "%u: slave %u %u %u %u\n",
|
||||
c2,
|
||||
sbus_bus_stat_stat_slave_start_counter_read(sc),
|
||||
sbus_bus_stat_stat_slave_done_counter_read(sc),
|
||||
sbus_bus_stat_stat_slave_rerun_counter_read(sc),
|
||||
sbus_bus_stat_stat_slave_early_error_counter_read(sc));
|
||||
device_printf(sc->sc_dev, "%u: master %u %u %u %u (0x%08x)\n",
|
||||
c2,
|
||||
sbus_bus_stat_stat_master_start_counter_read(sc),
|
||||
sbus_bus_stat_stat_master_done_counter_read(sc),
|
||||
sbus_bus_stat_stat_master_error_counter_read(sc),
|
||||
sbus_bus_stat_stat_master_rerun_counter_read(sc),
|
||||
sbus_bus_stat_sbus_master_error_virtual_read(sc));
|
||||
}
|
||||
sbus_bus_stat_stat_ctrl_write(sc, 0);
|
||||
if (sc->sc_enable)
|
||||
callout_schedule(&sc->sc_display, sc->sc_delay);
|
||||
}
|
||||
45
NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_stat.h
Normal file
45
NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_stat.h
Normal file
@ -0,0 +1,45 @@
|
||||
/* $NetBSD$ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2020 Romain Dolbeau <romain@dolbeau.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _SBUSFPGA_STAT_H_
|
||||
#define _SBUSFPGA_STAT_H_
|
||||
|
||||
struct sbusfpga_sbus_bus_stat_softc {
|
||||
device_t sc_dev; /* us as a device */
|
||||
u_int sc_rev; /* revision */
|
||||
int sc_node; /* PROM node ID */
|
||||
int sc_burst; /* DVMA burst size in effect */
|
||||
bus_space_tag_t sc_bustag; /* bus tag */
|
||||
bus_space_handle_t sc_bhregs_sbus_bus_stat; /* bus handle */
|
||||
int sc_bufsiz; /* Size of buffer */
|
||||
callout_t sc_display;
|
||||
int sc_delay;
|
||||
int sc_enable;
|
||||
};
|
||||
|
||||
#endif /* _SBUSFPGA_STAT_H_ */
|
||||
213
NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_trng.c
Normal file
213
NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_trng.c
Normal file
@ -0,0 +1,213 @@
|
||||
/* $NetBSD$ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2020 Romain Dolbeau <romain@dolbeau.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/device.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <sys/bus.h>
|
||||
#include <machine/autoconf.h>
|
||||
#include <sys/cpu.h>
|
||||
#include <sys/conf.h>
|
||||
|
||||
#include <sys/rndsource.h>
|
||||
|
||||
#include <dev/sbus/sbusvar.h>
|
||||
|
||||
#include <dev/sbus/sbusfpga_trng.h>
|
||||
|
||||
#include <machine/param.h>
|
||||
|
||||
int sbusfpga_trng_print(void *, const char *);
|
||||
int sbusfpga_trng_match(device_t, cfdata_t, void *);
|
||||
void sbusfpga_trng_attach(device_t, device_t, void *);
|
||||
|
||||
CFATTACH_DECL_NEW(sbusfpga_trng, sizeof(struct sbusfpga_trng_softc),
|
||||
sbusfpga_trng_match, sbusfpga_trng_attach, NULL, NULL);
|
||||
|
||||
dev_type_open(sbusfpga_trng_open);
|
||||
dev_type_close(sbusfpga_trng_close);
|
||||
dev_type_ioctl(sbusfpga_trng_ioctl);
|
||||
|
||||
|
||||
|
||||
const struct cdevsw sbusfpga_trng_cdevsw = {
|
||||
.d_open = sbusfpga_trng_open,
|
||||
.d_close = sbusfpga_trng_close,
|
||||
.d_read = noread,
|
||||
.d_write = nowrite,
|
||||
.d_ioctl = noioctl,
|
||||
.d_stop = nostop,
|
||||
.d_tty = notty,
|
||||
.d_poll = nopoll,
|
||||
.d_mmap = nommap,
|
||||
.d_kqfilter = nokqfilter,
|
||||
.d_discard = nodiscard,
|
||||
.d_flag = 0
|
||||
};
|
||||
|
||||
extern struct cfdriver sbusfpga_trng_cd;
|
||||
int
|
||||
sbusfpga_trng_open(dev_t dev, int flags, int mode, struct lwp *l)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
sbusfpga_trng_close(dev_t dev, int flags, int mode, struct lwp *l)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
sbusfpga_trng_print(void *aux, const char *busname)
|
||||
{
|
||||
|
||||
sbus_print(aux, busname);
|
||||
return (UNCONF);
|
||||
}
|
||||
|
||||
int
|
||||
sbusfpga_trng_match(device_t parent, cfdata_t cf, void *aux)
|
||||
{
|
||||
struct sbus_attach_args *sa = (struct sbus_attach_args *)aux;
|
||||
|
||||
return (strcmp("RDOL,neorv32trng", sa->sa_name) == 0);
|
||||
}
|
||||
|
||||
#define CONFIG_CSR_DATA_WIDTH 32
|
||||
// define CSR_LEDS_BASE & others to avoid defining the CSRs of HW we don't handle
|
||||
#define CSR_LEDS_BASE
|
||||
#define CSR_CURVE25519ENGINE_BASE
|
||||
#define CSR_DDRPHY_BASE
|
||||
#define CSR_EXCHANGE_WITH_MEM_BASE
|
||||
#define CSR_SBUS_BUS_STAT_BASE
|
||||
#define CSR_SDRAM_BASE
|
||||
#define CSR_SDBLOCK2MEM_BASE
|
||||
#define CSR_SDCORE_BASE
|
||||
#define CSR_SDIRQ_BASE
|
||||
#define CSR_SDMEM2BLOCK_BASE
|
||||
#define CSR_SDPHY_BASE
|
||||
//#define CSR_TRNG_BASE
|
||||
#include "dev/sbus/litex_csr.h"
|
||||
#undef CSR_LEDS_BASE
|
||||
#undef CSR_CURVE25519ENGINE_BASE
|
||||
#undef CSR_DDRPHY_BASE
|
||||
#undef CSR_EXCHANGE_WITH_MEM_BASE
|
||||
#undef CSR_SBUS_BUS_STAT_BASE
|
||||
#undef CSR_SDRAM_BASE
|
||||
#undef CSR_SDBLOCK2MEM_BASE
|
||||
#undef CSR_SDCORE_BASE
|
||||
#undef CSR_SDIRQ_BASE
|
||||
#undef CSR_SDMEM2BLOCK_BASE
|
||||
#undef CSR_SDPHY_BASE
|
||||
//#undef CSR_TRNG_BASE
|
||||
|
||||
static void
|
||||
sbusfpga_trng_getentropy(size_t nbytes, void *cookie) {
|
||||
struct sbusfpga_trng_softc *sc = cookie;
|
||||
size_t dbytes = 0;
|
||||
int failure = 0;
|
||||
while (nbytes > dbytes) {
|
||||
u_int32_t data = trng_data_read(sc);
|
||||
if (data) {
|
||||
rnd_add_data_sync(&sc->sc_rndsource, &data, 4, 32); // 32 is perhaps optimistic
|
||||
dbytes += 4;
|
||||
} else {
|
||||
failure ++;
|
||||
if (failure > (1+(dbytes/4))) { // something going on
|
||||
device_printf(sc->sc_dev, "out of entropy after %zd / %zd bytes\n", dbytes, nbytes);
|
||||
return;
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
if (((dbytes%32)==0) && (nbytes > dbytes))
|
||||
delay(1); // let the hardware breathes if the OS needs a lof of bytes
|
||||
}
|
||||
device_printf(sc->sc_dev, "gathered %zd bytes [%d]\n", dbytes, failure);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attach all the sub-devices we can find
|
||||
*/
|
||||
void
|
||||
sbusfpga_trng_attach(device_t parent, device_t self, void *aux)
|
||||
{
|
||||
struct sbus_attach_args *sa = aux;
|
||||
struct sbusfpga_trng_softc *sc = device_private(self);
|
||||
struct sbus_softc *sbsc = device_private(parent);
|
||||
int node;
|
||||
int sbusburst;
|
||||
|
||||
sc->sc_bustag = sa->sa_bustag;
|
||||
sc->sc_dev = self;
|
||||
|
||||
if (sbus_bus_map(sc->sc_bustag, sa->sa_slot, sa->sa_offset, sa->sa_size,
|
||||
BUS_SPACE_MAP_LINEAR, &sc->sc_bhregs_trng) != 0) {
|
||||
aprint_error(": cannot map registers\n");
|
||||
return;
|
||||
}
|
||||
|
||||
//sc->sc_buffer = bus_space_vaddr(sc->sc_bustag, sc->sc_bhregs_trng);
|
||||
sc->sc_bufsiz = sa->sa_size;
|
||||
|
||||
node = sc->sc_node = sa->sa_node;
|
||||
|
||||
/*
|
||||
* Get transfer burst size from PROM
|
||||
*/
|
||||
sbusburst = sbsc->sc_burst;
|
||||
if (sbusburst == 0)
|
||||
sbusburst = SBUS_BURST_32 - 1; /* 1->16 */
|
||||
|
||||
sc->sc_burst = prom_getpropint(node, "burst-sizes", -1);
|
||||
if (sc->sc_burst == -1)
|
||||
/* take SBus burst sizes */
|
||||
sc->sc_burst = sbusburst;
|
||||
|
||||
/* Clamp at parent's burst sizes */
|
||||
sc->sc_burst &= sbusburst;
|
||||
|
||||
aprint_normal("\n");
|
||||
aprint_normal_dev(self, "nid 0x%x, bustag %p, burst 0x%x (parent 0x%0x)\n",
|
||||
sc->sc_node,
|
||||
sc->sc_bustag,
|
||||
sc->sc_burst,
|
||||
sbsc->sc_burst);
|
||||
|
||||
trng_ctrl_write(sc, 0x02); // start the TRNG
|
||||
|
||||
rndsource_setcb(&sc->sc_rndsource, sbusfpga_trng_getentropy, sc);
|
||||
rnd_attach_source(&sc->sc_rndsource, device_xname(self), RND_TYPE_RNG, RND_FLAG_HASCB | RND_FLAG_COLLECT_VALUE);
|
||||
}
|
||||
43
NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_trng.h
Normal file
43
NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_trng.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* $NetBSD$ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2020 Romain Dolbeau <romain@dolbeau.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _SBUSFPGA_TRNG_H_
|
||||
#define _SBUSFPGA_TRNG_H_
|
||||
|
||||
struct sbusfpga_trng_softc {
|
||||
device_t sc_dev; /* us as a device */
|
||||
u_int sc_rev; /* revision */
|
||||
int sc_node; /* PROM node ID */
|
||||
int sc_burst; /* DVMA burst size in effect */
|
||||
bus_space_tag_t sc_bustag; /* bus tag */
|
||||
bus_space_handle_t sc_bhregs_trng; /* bus handle */
|
||||
int sc_bufsiz; /* Size of buffer */
|
||||
struct krndsource sc_rndsource;
|
||||
};
|
||||
|
||||
#endif /* _SBUSFPGA_TRNG_H_ */
|
||||
47
README.md
47
README.md
@ -2,7 +2,7 @@
|
||||
|
||||
## Goal
|
||||
|
||||
The goal of this repository is to be able to interface a modern (2020 era) [FPGA](https://en.wikipedia.org/wiki/Field-programmable_gate_array) with a [SBus](https://en.wikipedia.org/wiki/SBus) host. SBus was widely used in SPARCstation and compatibles system in the first halt of the 90s. It was progressively displaced by PCI from the mid-90s onward, and is thoroughly obsolete.
|
||||
The goal of this repository is to be able to interface a modern (2020 era) [FPGA](https://en.wikipedia.org/wiki/Field-programmable_gate_array) with a [SBus](https://en.wikipedia.org/wiki/SBus) host. SBus was widely used in SPARCstation and compatibles system in the first half of the 90s. It was progressively displaced by PCI from the mid-90s onward, and is thoroughly obsolete.
|
||||
|
||||
So unless you're a retrocomputing enthusiast with such a machine, this is useless. To be honest, even if you are such an enthusiast, it's probably not that useful...
|
||||
|
||||
@ -12,25 +12,50 @@ To save on PCB cost, the board is smaller than a 'true' SBus board; the hardware
|
||||
|
||||
## Current status
|
||||
|
||||
2021-03-21: The adapter board seems to work fine in two different SS20. Currently the embedded PROM code exposes three devices in the FPGA:
|
||||
2021-07-18: The old VHDL gateware has been replaced by a new Migen-based gateware, see below for details.
|
||||
|
||||
* "RDOL,cryptoengine": exposes a (way too large) polynomial multiplier to implement GCM mode and a AES block. Currently used to implement DMA-based acceleration of AES-256-CBC through /dev/crypto. Unfortunately OpenSSL doesn't support AES-256-GCM in the cryptodev engine, and disagree with NetBSD's /dev/crypto on how to implement AES-256-CTR. And the default SSH cannot use cryptodev, it closes all file descriptors after cryptodev has opened /dev/crypto... still WiP.
|
||||
|
||||
* "RDOL,trng": exposes a 5 MHz counter (didn't realize the SS20 already had a good counter) and a so-far-not-true TRNG (implemented by a PRNG). The 'true' random generators I've found make Vivado screams very loudly when synthesizing... anyway both works fine in NetBSD 9.0 as a timecounter and an entropy source (which a PRNG really isn't, I know). still WiP.
|
||||
|
||||
* "RDOL,sdcard": trying to expose the micro-sd card slot as a storage device, at first using SPI mode. So far reading seems to work, and NetBSD can see a Sun disklabel on the micro-sd card if it has been partitioned that way. Mounting a FAT filesystem read-only now works (with very little testing as of yet). Writing not working yet. Very much WiP.
|
||||
2021-08-22: Short version: the board enables a 256 MiB SDRAM disk (for fast swapping), a TRNG, a USB OHCI host controller (for USB peripherals) and a Curve25519 accelerator.
|
||||
|
||||
## The hardware
|
||||
|
||||
Directory 'sbus-to-ztex'
|
||||
|
||||
The custom board is a SBus-compliant (I hope...) board, designed to receive a [ZTex USB-FPGA Module 2.13](https://www.ztex.de/usb-fpga-2/usb-fpga-2.13.e.html) as a daughterboard. The ZTex module contains the actual FPGA (Artix-7), some RAM, programming hardware, etc. The SBus board contains level-shifters ICs to interface between the SBus signals and the FPGA, a serial header, some Leds, a JTAG header, and a micro-sd card slot.
|
||||
The custom board is a SBus-compliant (I hope...) board, designed to receive a [ZTex USB-FPGA Module 2.13](https://www.ztex.de/usb-fpga-2/usb-fpga-2.13.e.html) as a daughterboard. The ZTex module contains the actual FPGA (Artix-7), some RAM, programming hardware, etc. The SBus board contains level-shifters ICs to interface between the SBus signals and the FPGA, a serial header, some Leds, a JTAG header, and a micro-sd card slot. It only connects interrupt line 7 (highest priority) and 1 (lowest priority), which was a mistake (more interrupts are needed and 7 is too high-priority to use at this stage, so just the level 1 is usable), but otherwise supports every SBus feature except the optional parity (i.e. it can do both slave and master modes).
|
||||
|
||||
The PCB was designed with Kicad 5.0
|
||||
|
||||
## The gateware
|
||||
## The gateware (Migen)
|
||||
|
||||
Directory 'sbus-to-ztex-gateware'
|
||||
### Intro
|
||||
|
||||
The gateware was rewritten from scratch in the Migen language, choosen because that's what [Litex](https://github.com/enjoy-digital/litex/) uses.
|
||||
It implements a simple CPU-less Litex SoC built around a Wishbone bus, with a bridge between the SBus and the Wishbone.
|
||||
|
||||
A ROM, a SDRAM controller ([litedram](https://github.com/enjoy-digital/litedram) to the on-board DDR3), a TRNG (using the [NeoRV32](https://github.com/stnolting/neorv32) TRNG), an USB OHCI (host controller, using the Litex wrapper around the [SpinalHDL](https://github.com/SpinalHDL/SpinalHDL) implementation) and a Curve25519 Crypto Engine (taken from the [Betrusted.IO](https://betrusted.io/) project) are connected to that bus.
|
||||
|
||||
### Details
|
||||
|
||||
Master access to the SBus by the host are routed to the Wishbone to access the various CSRs / control registers of the devices.
|
||||
|
||||
The ROM doesn't do much beyond exposing the devices' existence and specifications to the host.
|
||||
|
||||
The SDRAM has its own custom DMA controller, using native Litedram DMA to the memory, and some FIFO to/from the SBus. A custom NetBSD driver exposes it as a drive on which you can swap. It's also usable as a 'fast', volatile disk (for e.g. /tmp or similar temporary filesystem). It could use a interrupt line, but the only usable one in the current HW design is in use by the USB.
|
||||
|
||||
The TRNG has a NetBSD driver to add entropy to the entropy pool.
|
||||
|
||||
The USB OHCI DMA is bridged from the Wishbone to the SBus by having the physical addresses of the Wishbone (that match the virtual addresses from NetBSD DVMA allocations) to the bridge. Reads are buffered by block of 16 bytes; currently writes are unbuffered (and somewhat slow, as they need a full SBus master cycle for every transaction of 32 bits or less). The standard NetBSD OHCI driver is used, with just a small custom SBus-OHCI driver mirroring the PCI-OHCI one. It uses the interrupt level 1 available on the board. As the board has no USB connectors, the D+ and D- lines are routed to the Serial header pins, those (and GND) are connected to a pair of pins of [Dolu1990's USB PMod](https://github.com/Dolu1990/pmod_usb_host_x4), and the associated USB port is connected to an external self-powered USB hub (which is the one supplying the VBus). It's quite ugly but it works (of course I should redesign the PCB with a proper USB connector and a VBus).
|
||||
|
||||
The Curve25519 Engine currently exposes an IOCTL to do the computation, which has yet to be integrated usefully in e.g. OpenSSL. It could use a interrupt line, but the only usable one in the current HW design is in use by the USB.
|
||||
|
||||
### Special Notes
|
||||
|
||||
Currently the design uses a Wishbone Crossbar Interconnect from Litex instead of a Shared Interconnect, as for some reason using a Shared Interconnect causes issues between devices (disabling the USB OHCI seem also to solve the issue, it generates a lot of cycles on the buses). I might be misusing Wishbone. With the Crossbar, all devices are usable simultaneously.
|
||||
|
||||
As not everything lives in the same clock domain, the design also use a Wishbone CDC, a wrapper around the one from [Verilog Wishbone Components](https://github.com/alexforencich/verilog-wishbone).
|
||||
|
||||
## The gateware (VHDL, obsolete)
|
||||
|
||||
Directory 'sbus-to-ztex-gateware', this is obsolete and replaced by the Migen gateware above.
|
||||
|
||||
The function embedded in the FPGA currently includes the PROM, lighting Led to display a 32-bits value, and a GHASH MAC (128 polynomial accumulator, used for the AES-GCM encryption scheme). The device is a fairly basic scale, but should be able to read from the PROM and read/write from the GCM space with any kind of SBus burst (1, 2, 4, 8 or 16 words).
|
||||
|
||||
@ -40,5 +65,5 @@ The gateware is currently synthesized with Vivado 2020.1
|
||||
|
||||
Directory 'NetBSD'
|
||||
|
||||
Some basic drivers for NetBSD 9.0/sparc to enable the deviced as described above.
|
||||
Some basic drivers for NetBSD 9.0/sparc to enable the devices as described above.
|
||||
|
||||
|
||||
2530
sbus-to-ztex-gateware-migen/engine.py
Normal file
2530
sbus-to-ztex-gateware-migen/engine.py
Normal file
File diff suppressed because one or more lines are too long
23
sbus-to-ztex-gateware-migen/engine_code/Cargo.toml
Normal file
23
sbus-to-ztex-gateware-migen/engine_code/Cargo.toml
Normal file
@ -0,0 +1,23 @@
|
||||
[package]
|
||||
name = "engine_code"
|
||||
version = "0.1.0"
|
||||
authors = ["Romain Dolbeau <romain@dolbeau.org>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
|
||||
[dependencies.engine25519-as]
|
||||
#git="https://github.com/betrusted-io/engine25519-as.git"
|
||||
#rev="6681e73c1fdc4a460b5ef9f9c7c91aef546d00f3"
|
||||
path = "/home/dolbeau/engine25519-as"
|
||||
|
||||
[dev-dependencies.engine25519-as]
|
||||
#git="https://github.com/betrusted-io/engine25519-as.git"
|
||||
#rev="6681e73c1fdc4a460b5ef9f9c7c91aef546d00f3"
|
||||
path = "/home/dolbeau/engine25519-as"
|
||||
|
||||
[[bin]]
|
||||
name = "engine_code"
|
||||
path = "engine_code.rs"
|
||||
1146
sbus-to-ztex-gateware-migen/engine_code/engine_code.rs
Normal file
1146
sbus-to-ztex-gateware-migen/engine_code/engine_code.rs
Normal file
File diff suppressed because it is too large
Load Diff
21
sbus-to-ztex-gateware-migen/forth_to_migen_rom.sh
Executable file
21
sbus-to-ztex-gateware-migen/forth_to_migen_rom.sh
Executable file
@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
PFX=prom_migen
|
||||
|
||||
rm -f ${PFX}.fc
|
||||
|
||||
# (export BP=~/SPARC/SBusFPGA/sbus-to-ztex/openfirmware ; toke ${PFX}.forth )
|
||||
|
||||
( export BP=`pwd`/openfirmware ; openfirmware/cpu/x86/Linux/forth openfirmware/cpu/x86/build/builder.dic prom_migen.bth ) 2>&1 | tee forth.log
|
||||
|
||||
rm -f /tmp/${PFX}.hexa
|
||||
|
||||
od --endian=big -w4 -x ${PFX}.fc | awk '{ print $2,$3"," }' >| /tmp/${PFX}.hexa
|
||||
|
||||
rm -f /tmp/${PFX}.txt_hexa
|
||||
|
||||
cat /tmp/${PFX}.hexa | sed -e 's/^\([a-f0-9][a-f0-9][a-f0-9][a-f0-9]\) \([a-f0-9][a-f0-9][a-f0-9][a-f0-9]\),/0x\1\2,/g' -e 's/^\([a-f0-9][a-f0-9]*\) ,/0x\10000,/' -e 's/^ ,/0x00000000,/' -e 's/\(0x[0-9a-fA-F]*\),/if (idx == 0):\n\treturn \1;/' > /tmp/${PFX}.txt_hexa
|
||||
|
||||
#echo "rom = ["
|
||||
#cat /tmp/${PFX}.txt_hexa
|
||||
#echo "]"
|
||||
382
sbus-to-ztex-gateware-migen/neorv32_trng_patched.vhd
Normal file
382
sbus-to-ztex-gateware-migen/neorv32_trng_patched.vhd
Normal file
@ -0,0 +1,382 @@
|
||||
-- # THIS IS NOT THE ORIGINAL FILE
|
||||
-- # THIS WAS MODIFIED TO EXPOSE THE TRNG IN LITEX
|
||||
-- # See the link in the copyright header to find the original file
|
||||
--
|
||||
--
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - True Random Number Generator (TRNG) >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # This unit implements a *true* random number generator which uses several ring oscillators as #
|
||||
-- # entropy source. The outputs of all chains are XORed and de-biased using a John von Neumann #
|
||||
-- # randomness extractor. The de-biased signal is further processed by a simple LFSR for improved #
|
||||
-- # whitening. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # BSD 3-Clause License #
|
||||
-- # #
|
||||
-- # Copyright (c) 2021, Stephan Nolting. All rights reserved. #
|
||||
-- # #
|
||||
-- # Redistribution and use in source and binary forms, with or without modification, are #
|
||||
-- # permitted provided that the following conditions are met: #
|
||||
-- # #
|
||||
-- # 1. Redistributions of source code must retain the above copyright notice, this list of #
|
||||
-- # conditions and the following disclaimer. #
|
||||
-- # #
|
||||
-- # 2. Redistributions in binary form must reproduce the above copyright notice, this list of #
|
||||
-- # conditions and the following disclaimer in the documentation and/or other materials #
|
||||
-- # provided with the distribution. #
|
||||
-- # #
|
||||
-- # 3. Neither the name of the copyright holder nor the names of its contributors may be used to #
|
||||
-- # endorse or promote products derived from this software without specific prior written #
|
||||
-- # permission. #
|
||||
-- # #
|
||||
-- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS #
|
||||
-- # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF #
|
||||
-- # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE #
|
||||
-- # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, #
|
||||
-- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
|
||||
-- # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED #
|
||||
-- # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING #
|
||||
-- # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED #
|
||||
-- # OF THE POSSIBILITY OF SUCH DAMAGE. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting #
|
||||
-- #################################################################################################
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library neorv32;
|
||||
-- use neorv32.neorv32_package.all;
|
||||
|
||||
entity neorv32_trng is
|
||||
port (
|
||||
-- host access --
|
||||
clk_i : in std_ulogic; -- global clock line
|
||||
-- addr_i : in std_ulogic_vector(31 downto 0); -- address
|
||||
rden_i : in std_ulogic; -- read enable
|
||||
wren_i : in std_ulogic; -- write enable
|
||||
data_i : in std_ulogic_vector(31 downto 0); -- data in
|
||||
data_o : out std_ulogic_vector(31 downto 0)--; -- data out
|
||||
-- ack_o : out std_ulogic -- transfer acknowledge
|
||||
);
|
||||
end neorv32_trng;
|
||||
|
||||
architecture neorv32_trng_rtl of neorv32_trng is
|
||||
|
||||
-- Advanced Configuration --------------------------------------------------------------------------------
|
||||
constant num_roscs_c : natural := 4; -- total number of ring oscillators
|
||||
constant num_inv_start_c : natural := 5; -- number of inverters in FIRST ring oscillator (has to be odd)
|
||||
constant num_inv_inc_c : natural := 2; -- number of inverters increment for each next ring oscillator (has to be even)
|
||||
constant lfsr_en_c : boolean := true; -- use LFSR-based post-processing
|
||||
constant lfsr_taps_c : std_ulogic_vector(7 downto 0) := "10111000"; -- Fibonacci post-processing LFSR feedback taps
|
||||
-- -------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- control register bits --
|
||||
constant ctrl_data_lsb_c : natural := 0; -- r/-: Random data byte LSB
|
||||
constant ctrl_data_msb_c : natural := 7; -- r/-: Random data byte MSB
|
||||
--
|
||||
constant ctrl_en_c : natural := 30; -- r/w: TRNG enable
|
||||
constant ctrl_valid_c : natural := 31; -- r/-: Output data valid
|
||||
|
||||
-- IO space: module base address --
|
||||
-- constant hi_abb_c : natural := index_size_f(io_size_c)-1; -- high address boundary bit
|
||||
-- constant lo_abb_c : natural := index_size_f(trng_size_c); -- low address boundary bit
|
||||
|
||||
-- copy/pasted from the rtl/core/neorv32_package.vhd file
|
||||
function xor_reduce_f(a : std_ulogic_vector) return std_ulogic is
|
||||
variable tmp_v : std_ulogic;
|
||||
begin
|
||||
tmp_v := '0';
|
||||
if (a'low < a'high) then -- not null range?
|
||||
for i in a'low to a'high loop
|
||||
tmp_v := tmp_v xor a(i);
|
||||
end loop; -- i
|
||||
end if;
|
||||
return tmp_v;
|
||||
end function xor_reduce_f;
|
||||
|
||||
|
||||
-- Component: Ring-Oscillator --
|
||||
component neorv32_trng_ring_osc
|
||||
generic (
|
||||
NUM_INV : natural := 16 -- number of inverters in chain
|
||||
);
|
||||
port (
|
||||
clk_i : in std_ulogic;
|
||||
enable_i : in std_ulogic; -- enable chain input
|
||||
enable_o : out std_ulogic; -- enable chain output
|
||||
data_o : out std_ulogic -- sync random bit
|
||||
);
|
||||
end component;
|
||||
|
||||
-- access control --
|
||||
signal acc_en : std_ulogic; -- module access enable
|
||||
-- signal wren : std_ulogic; -- full word write enable
|
||||
-- signal rden : std_ulogic; -- read enable
|
||||
|
||||
-- ring-oscillator array --
|
||||
signal osc_array_en_in : std_ulogic_vector(num_roscs_c-1 downto 0);
|
||||
signal osc_array_en_out : std_ulogic_vector(num_roscs_c-1 downto 0);
|
||||
signal osc_array_data : std_ulogic_vector(num_roscs_c-1 downto 0);
|
||||
|
||||
-- von-Neumann de-biasing --
|
||||
type debiasing_t is record
|
||||
sreg : std_ulogic_vector(1 downto 0);
|
||||
state : std_ulogic; -- process de-biasing every second cycle
|
||||
valid : std_ulogic; -- de-biased data
|
||||
data : std_ulogic; -- de-biased data valid
|
||||
end record;
|
||||
signal debiasing : debiasing_t;
|
||||
|
||||
-- (post-)processing core --
|
||||
type processing_t is record
|
||||
enable : std_ulogic; -- TRNG enable flag
|
||||
cnt : std_ulogic_vector(3 downto 0); -- bit counter
|
||||
sreg : std_ulogic_vector(7 downto 0); -- data shift register
|
||||
output : std_ulogic_vector(7 downto 0); -- output register
|
||||
valid : std_ulogic; -- data output valid flag
|
||||
end record;
|
||||
signal processing : processing_t;
|
||||
|
||||
begin
|
||||
|
||||
-- Sanity Checks --------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
assert not (num_roscs_c = 0) report "NEORV32 PROCESSOR CONFIG ERROR: TRNG - Total number of ring-oscillators has to be >0." severity error;
|
||||
assert not ((num_inv_start_c mod 2) = 0) report "NEORV32 PROCESSOR CONFIG ERROR: TRNG - Number of inverters in fisrt ring has to be odd." severity error;
|
||||
assert not ((num_inv_inc_c mod 2) /= 0) report "NEORV32 PROCESSOR CONFIG ERROR: TRNG - Number of inverters increment for each next ring has to be even." severity error;
|
||||
|
||||
|
||||
-- Access Control -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = trng_base_c(hi_abb_c downto lo_abb_c)) else '0';
|
||||
-- wren <= acc_en and wren_i;
|
||||
-- rden <= acc_en and rden_i;
|
||||
|
||||
-- Read/Write Access ----------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
rw_access: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
-- ack_o <= wren_i or rden_i;
|
||||
-- write access --
|
||||
if (wren_i = '1') then
|
||||
processing.enable <= data_i(ctrl_en_c);
|
||||
end if;
|
||||
-- read access --
|
||||
-- data_o <= (others => '0');
|
||||
if (rden_i = '1') then
|
||||
data_o(ctrl_data_msb_c downto ctrl_data_lsb_c) <= processing.output;
|
||||
data_o(ctrl_en_c) <= processing.enable;
|
||||
data_o(ctrl_valid_c) <= processing.valid;
|
||||
end if;
|
||||
end if;
|
||||
end process rw_access;
|
||||
|
||||
|
||||
-- Entropy Source -------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
neorv32_trng_ring_osc_inst:
|
||||
for i in 0 to num_roscs_c-1 generate
|
||||
neorv32_trng_ring_osc_inst_i: neorv32_trng_ring_osc
|
||||
generic map (
|
||||
NUM_INV => num_inv_start_c + (i*num_inv_inc_c) -- number of inverters in chain
|
||||
)
|
||||
port map (
|
||||
clk_i => clk_i,
|
||||
enable_i => osc_array_en_in(i),
|
||||
enable_o => osc_array_en_out(i),
|
||||
data_o => osc_array_data(i)
|
||||
);
|
||||
end generate;
|
||||
|
||||
-- RO enable chain --
|
||||
array_intercon: process(processing.enable, osc_array_en_out)
|
||||
begin
|
||||
for i in 0 to num_roscs_c-1 loop
|
||||
if (i = 0) then -- start of enable chain
|
||||
osc_array_en_in(i) <= processing.enable;
|
||||
else
|
||||
osc_array_en_in(i) <= osc_array_en_out(i-1);
|
||||
end if;
|
||||
end loop; -- i
|
||||
end process array_intercon;
|
||||
|
||||
|
||||
-- John von Neumann De-Biasing ------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
neumann_debiasing_sync: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
debiasing.sreg <= debiasing.sreg(debiasing.sreg'left-1 downto 0) & xor_reduce_f(osc_array_data);
|
||||
debiasing.state <= (not debiasing.state) and osc_array_en_out(num_roscs_c-1); -- start toggling when last RO is enabled -> process in every second cycle
|
||||
end if;
|
||||
end process neumann_debiasing_sync;
|
||||
|
||||
-- Edge detector --
|
||||
neumann_debiasing_comb: process(debiasing)
|
||||
variable tmp_v : std_ulogic_vector(2 downto 0);
|
||||
begin
|
||||
-- check groups of two non-overlapping bits from the input stream
|
||||
tmp_v := debiasing.state & debiasing.sreg;
|
||||
case tmp_v is
|
||||
when "101" => debiasing.valid <= '1'; debiasing.data <= '1'; -- rising edge -> '1'
|
||||
when "110" => debiasing.valid <= '1'; debiasing.data <= '0'; -- falling edge -> '0'
|
||||
when others => debiasing.valid <= '0'; debiasing.data <= '0'; -- no valid data
|
||||
end case;
|
||||
end process neumann_debiasing_comb;
|
||||
|
||||
|
||||
-- Processing Core ------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
processing_core: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
-- sample random data bit and apply post-processing --
|
||||
if (processing.enable = '0') then
|
||||
processing.cnt <= (others => '0');
|
||||
processing.sreg <= (others => '0');
|
||||
elsif (debiasing.valid = '1') then -- valid random sample?
|
||||
if (processing.cnt = "1000") then
|
||||
processing.cnt <= (others => '0');
|
||||
else
|
||||
processing.cnt <= std_ulogic_vector(unsigned(processing.cnt) + 1);
|
||||
end if;
|
||||
if (lfsr_en_c = true) then -- LFSR post-processing
|
||||
processing.sreg <= processing.sreg(processing.sreg'left-1 downto 0) & ((not xor_reduce_f(processing.sreg and lfsr_taps_c)) xnor debiasing.data);
|
||||
else -- NO post-processing
|
||||
processing.sreg <= processing.sreg(processing.sreg'left-1 downto 0) & debiasing.data;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- data output register --
|
||||
if (processing.cnt = "1000") then
|
||||
processing.output <= processing.sreg;
|
||||
end if;
|
||||
|
||||
-- data ready/valid flag --
|
||||
if (processing.cnt = "1000") then -- new sample ready?
|
||||
processing.valid <= '1';
|
||||
elsif (processing.enable = '0') or (rden_i = '1') then -- clear when deactivated or on data read
|
||||
processing.valid <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end process processing_core;
|
||||
|
||||
|
||||
end neorv32_trng_rtl;
|
||||
|
||||
|
||||
-- ############################################################################################################################
|
||||
-- ############################################################################################################################
|
||||
|
||||
|
||||
-- #################################################################################################
|
||||
-- # << NEORV32 - True Random Number Generator (TRNG) - Ring-Oscillator-Based Entropy Source >> #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # An inverter chain (ring oscillator) is used as entropy source. #
|
||||
-- # The inverter chain is constructed as an "asynchronous" LFSR. The single inverters are #
|
||||
-- # connected via latches that are used to enable/disable the TRNG. Also, these latches are used #
|
||||
-- # as additional delay element. By using unique enable signals for each latch, the synthesis #
|
||||
-- # tool cannot "optimize" (=remove) any of the inverters out of the design. Furthermore, the #
|
||||
-- # latches prevent the synthesis tool from detecting combinatorial loops. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # BSD 3-Clause License #
|
||||
-- # #
|
||||
-- # Copyright (c) 2021, Stephan Nolting. All rights reserved. #
|
||||
-- # #
|
||||
-- # Redistribution and use in source and binary forms, with or without modification, are #
|
||||
-- # permitted provided that the following conditions are met: #
|
||||
-- # #
|
||||
-- # 1. Redistributions of source code must retain the above copyright notice, this list of #
|
||||
-- # conditions and the following disclaimer. #
|
||||
-- # #
|
||||
-- # 2. Redistributions in binary form must reproduce the above copyright notice, this list of #
|
||||
-- # conditions and the following disclaimer in the documentation and/or other materials #
|
||||
-- # provided with the distribution. #
|
||||
-- # #
|
||||
-- # 3. Neither the name of the copyright holder nor the names of its contributors may be used to #
|
||||
-- # endorse or promote products derived from this software without specific prior written #
|
||||
-- # permission. #
|
||||
-- # #
|
||||
-- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS #
|
||||
-- # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF #
|
||||
-- # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE #
|
||||
-- # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, #
|
||||
-- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
|
||||
-- # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED #
|
||||
-- # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING #
|
||||
-- # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED #
|
||||
-- # OF THE POSSIBILITY OF SUCH DAMAGE. #
|
||||
-- # ********************************************************************************************* #
|
||||
-- # The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting #
|
||||
-- #################################################################################################
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library neorv32;
|
||||
-- use neorv32.neorv32_package.all;
|
||||
|
||||
entity neorv32_trng_ring_osc is
|
||||
generic (
|
||||
NUM_INV : natural := 15 -- number of inverters in chain
|
||||
);
|
||||
port (
|
||||
clk_i : in std_ulogic;
|
||||
enable_i : in std_ulogic; -- enable chain input
|
||||
enable_o : out std_ulogic; -- enable chain output
|
||||
data_o : out std_ulogic -- sync random bit
|
||||
);
|
||||
end neorv32_trng_ring_osc;
|
||||
|
||||
architecture neorv32_trng_ring_osc_rtl of neorv32_trng_ring_osc is
|
||||
|
||||
signal inv_chain : std_ulogic_vector(NUM_INV-1 downto 0); -- oscillator chain
|
||||
signal enable_sreg : std_ulogic_vector(NUM_INV-1 downto 0); -- enable shift register
|
||||
signal sync_ff : std_ulogic_vector(1 downto 0); -- output signal synchronizer
|
||||
|
||||
begin
|
||||
|
||||
-- Ring Oscillator ------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
ring_osc: process(enable_i, enable_sreg, inv_chain)
|
||||
begin
|
||||
-- Using individual enable signals for each inverter - derived from a shift register - to prevent the synthesis tool
|
||||
-- from removing all but one inverter (since they implement "logical identical functions").
|
||||
-- This also allows to make the TRNG platform independent.
|
||||
for i in 0 to NUM_INV-1 loop -- inverters in chain
|
||||
if (enable_i = '0') then -- start with a defined state (latch reset)
|
||||
inv_chain(i) <= '0';
|
||||
elsif (enable_sreg(i) = '1') then
|
||||
-- here we have the inverter chain --
|
||||
if (i = NUM_INV-1) then -- left-most inverter?
|
||||
inv_chain(i) <= not inv_chain(0);
|
||||
else
|
||||
inv_chain(i) <= not inv_chain(i+1);
|
||||
end if;
|
||||
end if;
|
||||
end loop; -- i
|
||||
end process ring_osc;
|
||||
|
||||
|
||||
-- Control --------------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
ctrl_unit: process(clk_i)
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
enable_sreg <= enable_sreg(enable_sreg'left-1 downto 0) & enable_i; -- activate right-most inverter first
|
||||
sync_ff <= sync_ff(0) & inv_chain(0); -- synchronize to prevent metastability
|
||||
end if;
|
||||
end process ctrl_unit;
|
||||
|
||||
-- output for "enable chain" --
|
||||
enable_o <= enable_sreg(enable_sreg'left);
|
||||
|
||||
-- rnd output --
|
||||
data_o <= sync_ff(1);
|
||||
|
||||
|
||||
end neorv32_trng_ring_osc_rtl;
|
||||
1125
sbus-to-ztex-gateware-migen/netbsd_csr.h
Normal file
1125
sbus-to-ztex-gateware-migen/netbsd_csr.h
Normal file
File diff suppressed because it is too large
Load Diff
14
sbus-to-ztex-gateware-migen/prom_csr.fth
Normal file
14
sbus-to-ztex-gateware-migen/prom_csr.fth
Normal file
@ -0,0 +1,14 @@
|
||||
\ auto-generated base regions for CSRs in the PROM
|
||||
h# 40000 constant sbusfpga_csraddr_leds
|
||||
h# 41000 constant sbusfpga_csraddr_curve25519engine
|
||||
h# 42000 constant sbusfpga_csraddr_ddrphy
|
||||
h# 43000 constant sbusfpga_csraddr_exchange_with_mem
|
||||
h# 44000 constant sbusfpga_csraddr_sbus_bus_stat
|
||||
h# 45000 constant sbusfpga_csraddr_sdram
|
||||
h# 46000 constant sbusfpga_csraddr_trng
|
||||
h# 80000 constant sbusfpga_regionaddr_usb_host_ctrl
|
||||
h# 0 constant sbusfpga_regionaddr_prom
|
||||
h# 80000000 constant sbusfpga_regionaddr_main_ram
|
||||
h# fc000000 constant sbusfpga_regionaddr_usb_fake_dma
|
||||
h# a0000 constant sbusfpga_regionaddr_curve25519engine
|
||||
h# 40000 constant sbusfpga_regionaddr_csr
|
||||
31
sbus-to-ztex-gateware-migen/prom_migen.bth
Normal file
31
sbus-to-ztex-gateware-migen/prom_migen.bth
Normal file
@ -0,0 +1,31 @@
|
||||
purpose: Load file for SBusFPGA
|
||||
|
||||
command: &builder &this
|
||||
|
||||
\ in: ${BP}/dev/usb2/device/hub/build/hub.fc
|
||||
\ in: ${BP}/dev/usb2/device/generic/build/generic.fc
|
||||
\ in: ${BP}/dev/usb2/device/net/build/usbnet.fc
|
||||
\ in: ${BP}/dev/usb2/device/serial/build/usbserial.fc
|
||||
\ in: ${BP}/dev/usb2/device/storage/build/usbstorage.fc
|
||||
\ in: ${BP}/dev/usb2/device/keyboard/build/usbkbd.fc
|
||||
\ in: ${BP}/dev/usb2/device/mouse/build/usbmouse.fc
|
||||
|
||||
build-now
|
||||
|
||||
\ silent on
|
||||
|
||||
begin-tokenizing prom_migen.fc
|
||||
|
||||
fload prom_migen.fth
|
||||
|
||||
end-tokenizing
|
||||
|
||||
\ h# 8000 to reserved-start
|
||||
\ h# f000 to reserved-end
|
||||
\ " ${BP}/dev/usb2/device/hub/build/hub.fc" " usb,class9" $add-dropin
|
||||
\ " ${BP}/dev/usb2/device/generic/build/generic.fc" " usbdevice" $add-deflated-dropin
|
||||
\ " ${BP}/dev/usb2/device/net/build/usbnet.fc" " usbnet" $add-deflated-dropin
|
||||
\ " ${BP}/dev/usb2/device/keyboard/build/usbkbd.fc" " usb,class3,1,1" $add-deflated-dropin
|
||||
\ " ${BP}/dev/usb2/device/mouse/build/usbmouse.fc" " usb,class3,1,2" $add-deflated-dropin
|
||||
\ " ${BP}/dev/usb2/device/serial/build/usbserial.fc" " usbserial" $add-deflated-dropin
|
||||
\ " ${BP}/dev/usb2/device/storage/build/usbstorage.fc" " usbstorage" $add-deflated-dropin
|
||||
247
sbus-to-ztex-gateware-migen/prom_migen.fth
Normal file
247
sbus-to-ztex-gateware-migen/prom_migen.fth
Normal file
@ -0,0 +1,247 @@
|
||||
fcode-version2
|
||||
|
||||
\ loads constants
|
||||
fload prom_csr.fth
|
||||
|
||||
\ fload v2compat.fth
|
||||
|
||||
\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ LEDs
|
||||
\ Absolute minimal stuff; name & registers def.
|
||||
" RDOL,led" device-name
|
||||
my-address sbusfpga_csraddr_leds + my-space h# 4 reg
|
||||
\ we don't support ET or HWORD
|
||||
h# 7d xdrint " slave-burst-sizes" attribute
|
||||
h# 7d xdrint " burst-sizes" attribute
|
||||
|
||||
headers
|
||||
-1 instance value led-virt
|
||||
my-address constant my-sbus-address
|
||||
my-space constant my-sbus-space
|
||||
|
||||
: map-in ( adr space size -- virt ) " map-in" $call-parent ;
|
||||
: map-out ( virt size -- ) " map-out" $call-parent ;
|
||||
|
||||
: map-in-led ( -- ) my-sbus-address sbusfpga_csraddr_leds + my-sbus-space h# 4 map-in is led-virt ;
|
||||
: map-out-led ( -- ) led-virt h# 4 map-out ;
|
||||
|
||||
: setled! ( pattern -- )
|
||||
map-in-led
|
||||
led-virt l! ( pattern virt -- )
|
||||
map-out-led
|
||||
;
|
||||
|
||||
\ h# a5 setled!
|
||||
|
||||
\ OpenBIOS tokenizer won't accept finish-device without new-device
|
||||
\ Cheat by using the tokenizer so we can do OpenBoot 2.x siblings
|
||||
\ tokenizer[ 01 emit-byte h# 27 emit-byte h# 01 emit-byte h# 1f emit-byte ]tokenizer
|
||||
\ The OpenFirmware tokenizer does accept the 'clean' syntax
|
||||
finish-device
|
||||
\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ USB OHCI
|
||||
new-device
|
||||
|
||||
\ Absolute minimal stuff; name & registers def.
|
||||
" generic-ohci" device-name
|
||||
|
||||
\ USB registers are in the device space, not the CSR space
|
||||
my-address sbusfpga_regionaddr_usb_host_ctrl + my-space h# 1000 reg
|
||||
\ we don't support ET or anything non-32bits
|
||||
h# 7c xdrint " slave-burst-sizes" attribute
|
||||
h# 7c xdrint " burst-sizes" attribute
|
||||
|
||||
1 xdrint " interrupts" attribute
|
||||
|
||||
headers
|
||||
-1 instance value regs-virt
|
||||
my-address constant my-sbus-address
|
||||
my-space constant my-sbus-space
|
||||
|
||||
: map-in ( adr space size -- virt ) " map-in" $call-parent ;
|
||||
: map-out ( virt size -- ) " map-out" $call-parent ;
|
||||
|
||||
: map-in-regs ( -- ) my-sbus-address sbusfpga_regionaddr_usb_host_ctrl + my-sbus-space h# 1000 map-in is regs-virt ;
|
||||
: map-out-regs ( -- ) regs-virt h# 1000 map-out ;
|
||||
|
||||
: my-reset! ( -- )
|
||||
map-in-regs
|
||||
00000001 regs-virt h# 4 + l! ( -- ) ( reset the HC )
|
||||
00000000 regs-virt h# 18 + l! ( -- ) ( reset HCCA & friends )
|
||||
00000000 regs-virt h# 1c + l! ( -- )
|
||||
00000000 regs-virt h# 20 + l! ( -- )
|
||||
00000000 regs-virt h# 24 + l! ( -- )
|
||||
00000000 regs-virt h# 28 + l! ( -- )
|
||||
00000000 regs-virt h# 2c + l! ( -- )
|
||||
00000000 regs-virt h# 30 + l! ( -- )
|
||||
map-out-regs
|
||||
;
|
||||
|
||||
my-reset!
|
||||
|
||||
\ " ohci" encode-string " device_type" property
|
||||
\ fload openfirmware/dev/usb2/hcd/ohci/loadpkg-sbus.fth
|
||||
\ open
|
||||
|
||||
\ OpenBIOS tokenizer won't accept finish-device without new-device
|
||||
\ Cheat by using the tokenizer so we can do OpenBoot 2.x siblings
|
||||
\ tokenizer[ 01 emit-byte h# 27 emit-byte h# 01 emit-byte h# 1f emit-byte ]tokenizer
|
||||
\ The OpenFirmware tokenizer does accept the 'clean' syntax
|
||||
finish-device
|
||||
\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ SDRAM
|
||||
new-device
|
||||
|
||||
\ Absolute minimal stuff; name & registers def.
|
||||
" RDOL,sdram" device-name
|
||||
\ three pages of registers:
|
||||
my-address sbusfpga_csraddr_ddrphy + my-space xdrphys \ Offset#1
|
||||
h# 1000 xdrint xdr+ \ Merge size#1
|
||||
my-address sbusfpga_csraddr_sdram + my-space xdrphys xdr+ \ Merge offset#2
|
||||
h# 1000 xdrint xdr+ \ Merge size#2
|
||||
my-address sbusfpga_csraddr_exchange_with_mem + my-space xdrphys xdr+ \ Merge offset#3
|
||||
h# 1000 xdrint xdr+ \ Merge size#3
|
||||
\ my-address sbusfpga_regionaddr_main_ram + my-space xdrphys xdr+ \ Merge offset#4
|
||||
\ h# 10000 xdrint xdr+ \ Merge size#4
|
||||
" reg" attribute
|
||||
|
||||
\ we don't support ET or anything non-32bits
|
||||
h# 7c xdrint " slave-burst-sizes" attribute
|
||||
h# 7c xdrint " burst-sizes" attribute
|
||||
|
||||
headers
|
||||
-1 instance value mregs-ddrphy-virt
|
||||
-1 instance value mregs-sdram-virt
|
||||
-1 instance value mregs-exchange_with_mem-virt
|
||||
my-address constant my-sbus-address
|
||||
my-space constant my-sbus-space
|
||||
: map-in ( adr space size -- virt ) " map-in" $call-parent ;
|
||||
: map-out ( virt size -- ) " map-out" $call-parent ;
|
||||
|
||||
: map-in-mregs ( -- )
|
||||
my-sbus-address sbusfpga_csraddr_ddrphy + my-sbus-space h# 1000 map-in is mregs-ddrphy-virt
|
||||
my-sbus-address sbusfpga_csraddr_sdram + my-sbus-space h# 1000 map-in is mregs-sdram-virt
|
||||
my-sbus-address sbusfpga_csraddr_exchange_with_mem + my-sbus-space h# 1000 map-in is mregs-exchange_with_mem-virt
|
||||
;
|
||||
: map-out-mregs ( -- )
|
||||
mregs-ddrphy-virt h# 1000 map-out
|
||||
mregs-sdram-virt h# 1000 map-out
|
||||
mregs-exchange_with_mem-virt h# 1000 map-out
|
||||
;
|
||||
|
||||
\ fload sdram_init.fth
|
||||
|
||||
\ init!
|
||||
|
||||
|
||||
\ OpenBIOS tokenizer won't accept finish-device without new-device
|
||||
\ Cheat by using the tokenizer so we can do OpenBoot 2.x siblings
|
||||
\ tokenizer[ 01 emit-byte h# 27 emit-byte h# 01 emit-byte h# 1f emit-byte ]tokenizer
|
||||
\ The OpenFirmware tokenizer does accept the 'clean' syntax
|
||||
finish-device
|
||||
\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ TRNG
|
||||
new-device
|
||||
|
||||
\ Absolute minimal stuff; name & registers def.
|
||||
" RDOL,neorv32trng" device-name
|
||||
|
||||
my-address sbusfpga_csraddr_trng + my-space h# 8 reg
|
||||
\ we don't support ET or HWORD
|
||||
h# 7d xdrint " slave-burst-sizes" attribute
|
||||
h# 7d xdrint " burst-sizes" attribute
|
||||
|
||||
headers
|
||||
-1 instance value trng-virt
|
||||
my-address constant my-sbus-address
|
||||
my-space constant my-sbus-space
|
||||
|
||||
: map-in ( adr space size -- virt ) " map-in" $call-parent ;
|
||||
: map-out ( virt size -- ) " map-out" $call-parent ;
|
||||
|
||||
: map-in-trng ( -- ) my-sbus-address sbusfpga_csraddr_trng + my-sbus-space h# 8 map-in is trng-virt ;
|
||||
: map-out-trng ( -- ) trng-virt h# 8 map-out ;
|
||||
|
||||
: disabletrng! ( -- )
|
||||
map-in-trng
|
||||
1 trng-virt l! ( pattern virt -- )
|
||||
map-out-trng
|
||||
;
|
||||
|
||||
disabletrng!
|
||||
|
||||
|
||||
\ OpenBIOS tokenizer won't accept finish-device without new-device
|
||||
\ Cheat by using the tokenizer so we can do OpenBoot 2.x siblings
|
||||
\ tokenizer[ 01 emit-byte h# 27 emit-byte h# 01 emit-byte h# 1f emit-byte ]tokenizer
|
||||
\ The OpenFirmware tokenizer does accept the 'clean' syntax
|
||||
finish-device
|
||||
\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ CURVE25519
|
||||
new-device
|
||||
|
||||
\ Absolute minimal stuff; name & registers def.
|
||||
" betrustedc25519e" device-name
|
||||
|
||||
\ one page of CSR registers, plus the memory
|
||||
\ we might want to replace the slave memory access
|
||||
\ by another instance of exchange_with_mem ?
|
||||
\ we split the memory space in two
|
||||
\ 0x1000 @ 0x0 for the microcode
|
||||
\ 0x10000 @ 0x10000 for the register file
|
||||
my-address sbusfpga_csraddr_curve25519engine + my-space xdrphys \ Offset#1
|
||||
h# 1000 xdrint xdr+ \ Merge size#1
|
||||
my-address sbusfpga_regionaddr_curve25519engine + my-space xdrphys xdr+ \ Merge offset#2
|
||||
h# 1000 xdrint xdr+ \ Merge size#2
|
||||
my-address sbusfpga_regionaddr_curve25519engine h# 10000 + + my-space xdrphys xdr+ \ Merge offset#3
|
||||
h# 10000 xdrint xdr+ \ Merge size#3
|
||||
" reg" attribute
|
||||
|
||||
\ we don't support ET or HWORD
|
||||
h# 7d xdrint " slave-burst-sizes" attribute
|
||||
h# 7d xdrint " burst-sizes" attribute
|
||||
|
||||
headers
|
||||
-1 instance value curve25519engine-virt
|
||||
-1 instance value curve25519engine-microcode-virt
|
||||
-1 instance value curve25519engine-regfile-virt
|
||||
my-address constant my-sbus-address
|
||||
my-space constant my-sbus-space
|
||||
|
||||
: map-in ( adr space size -- virt ) " map-in" $call-parent ;
|
||||
: map-out ( virt size -- ) " map-out" $call-parent ;
|
||||
|
||||
: map-in-curve25519engine ( -- )
|
||||
my-sbus-address sbusfpga_csraddr_curve25519engine + my-sbus-space h# 1000 map-in is curve25519engine-virt
|
||||
my-sbus-address sbusfpga_regionaddr_curve25519engine + my-sbus-space h# 1000 map-in is curve25519engine-microcode-virt
|
||||
my-sbus-address sbusfpga_regionaddr_curve25519engine h# 10000 + + my-sbus-space h# 10000 map-in is curve25519engine-regfile-virt
|
||||
;
|
||||
: map-out-curve25519engine ( -- )
|
||||
curve25519engine-virt h# 1000 map-out
|
||||
curve25519engine-microcode-virt h# 1000 map-out
|
||||
curve25519engine-regfile-virt h# 10000 map-out
|
||||
;
|
||||
|
||||
\ OpenBIOS tokenizer won't accept finish-device without new-device
|
||||
\ Cheat by using the tokenizer so we can do OpenBoot 2.x siblings
|
||||
\ tokenizer[ 01 emit-byte h# 27 emit-byte h# 01 emit-byte h# 1f emit-byte ]tokenizer
|
||||
\ The OpenFirmware tokenizer does accept the 'clean' syntax
|
||||
finish-device
|
||||
\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ STAT
|
||||
new-device
|
||||
|
||||
\ Absolute minimal stuff; name & registers def.
|
||||
" RDOL,sbusstat" device-name
|
||||
|
||||
my-address sbusfpga_csraddr_sbus_bus_stat + my-space h# 100 reg
|
||||
\ we don't support ET or HWORD
|
||||
h# 7d xdrint " slave-burst-sizes" attribute
|
||||
h# 7d xdrint " burst-sizes" attribute
|
||||
|
||||
headers
|
||||
-1 instance value sbus_bus_stat-virt
|
||||
my-address constant my-sbus-address
|
||||
my-space constant my-sbus-space
|
||||
|
||||
: map-in ( adr space size -- virt ) " map-in" $call-parent ;
|
||||
: map-out ( virt size -- ) " map-out" $call-parent ;
|
||||
|
||||
: map-in-sbus_bus_stat ( -- ) my-sbus-address sbusfpga_csraddr_sbus_bus_stat + my-sbus-space h# 100 map-in is sbus_bus_stat-virt ;
|
||||
: map-out-sbus_bus_stat ( -- ) sbus_bus_stat-virt h# 100 map-out ;
|
||||
|
||||
end0
|
||||
239
sbus-to-ztex-gateware-migen/sbus_to_fpga_blk_dma.py
Normal file
239
sbus-to-ztex-gateware-migen/sbus_to_fpga_blk_dma.py
Normal file
@ -0,0 +1,239 @@
|
||||
from migen import *
|
||||
from migen.genlib.fifo import *
|
||||
from migen.genlib.cdc import BusSynchronizer
|
||||
from litex.soc.interconnect.csr import *
|
||||
from litex.soc.interconnect import wishbone
|
||||
|
||||
# width of towrite_fifo is '32'+'burst_size * 32' (vaddr + data)
|
||||
# so the SBus DMA has all the needed info
|
||||
# width of fromsbus_req_fifo is 'blk_addr_width' + 'vaddr' (blk_addr + vaddr)
|
||||
# width of fromsbus_fifo is 'blk_addr_width' + 'burst_size * 32' (blk_addr + data)
|
||||
# the blk_addr does the round-trip to accompany the data
|
||||
class ExchangeWithMem(Module, AutoCSR):
|
||||
def __init__(self, soc, tosbus_fifo, fromsbus_fifo, fromsbus_req_fifo, dram_dma_writer, dram_dma_reader, burst_size = 8, do_checksum = False):
|
||||
#self.wishbone_r_slave = wishbone.Interface(data_width=soc.bus.data_width)
|
||||
#self.wishbone_w_slave = wishbone.Interface(data_width=soc.bus.data_width)
|
||||
self.tosbus_fifo = tosbus_fifo
|
||||
self.fromsbus_fifo = fromsbus_fifo
|
||||
self.fromsbus_req_fifo = fromsbus_req_fifo
|
||||
self.dram_dma_writer = dram_dma_writer
|
||||
self.dram_dma_reader = dram_dma_reader
|
||||
|
||||
data_width = burst_size * 4
|
||||
data_width_bits = burst_size * 32
|
||||
blk_addr_width = 32 - log2_int(data_width) # 27 for burst_size == 8
|
||||
|
||||
assert(len(self.dram_dma_writer.sink.data) == data_width_bits)
|
||||
assert(len(self.dram_dma_reader.source.data) == data_width_bits)
|
||||
|
||||
#self.wishbone_r_master = wishbone.Interface(data_width=data_width_bits)
|
||||
#self.wishbone_w_master = wishbone.Interface(data_width=data_width_bits)
|
||||
|
||||
#self.submodules += wishbone.Converter(self.wishbone_r_master, self.wishbone_r_slave)
|
||||
#self.submodules += wishbone.Converter(self.wishbone_w_master, self.wishbone_w_slave)
|
||||
|
||||
print("ExchangeWithMem: data_width = {}, data_width_bits = {}, blk_addr_width = {}\n".format(data_width, data_width_bits, blk_addr_width))
|
||||
print("ExchangeWithMem: tosbus_fifo width = {}, fromsbus_fifo width = {}, fromsbus_req_fifo width = {}\n".format(len(tosbus_fifo.din), len(fromsbus_fifo.dout), len(fromsbus_req_fifo.din)))
|
||||
|
||||
local_r_addr = Signal(blk_addr_width)
|
||||
dma_r_addr = Signal(32)
|
||||
#local_r_widx = Signal(log2_int(burst_size)) # so width is 3 for burst_size == 8
|
||||
#local_r_buffer = Signal(data_width_bits)
|
||||
|
||||
local_w_addr = Signal(blk_addr_width)
|
||||
dma_w_addr = Signal(32)
|
||||
#local_w_widx = Signal(log2_int(burst_size)) # so width is 3 for burst_size == 8
|
||||
#local_w_buffer = Signal(data_width_bits)
|
||||
|
||||
max_block_bits=16
|
||||
|
||||
# CSRConstant do not seem to appear in the CSR Map, but they need to be accessible to the OS driver
|
||||
#self.blk_size = CSRConstant(value=data_width) # report the block size to the SW layer
|
||||
#self.blk_base = CSRConstant(value=soc.wb_mem_map["main_ram"] >> log2_int(data_width)) # report where the blk starts
|
||||
self.blk_size = CSRStatus(32) # report the block size to the SW layer
|
||||
self.blk_base = CSRStatus(32) # report where the blk starts
|
||||
self.mem_size = CSRStatus(32) # report how much memory we have
|
||||
self.comb += self.blk_size.status.eq(data_width)
|
||||
self.comb += self.blk_base.status.eq(soc.wb_mem_map["main_ram"] >> log2_int(data_width))
|
||||
self.comb += self.mem_size.status.eq((256 * 1024 * 1024) >> log2_int(data_width)) # is it already available from mem_regions ?
|
||||
|
||||
self.blk_addr = CSRStorage(32, description = "SDRAM Block address to read/write from Wishbone memory (block of size {})".format(data_width))
|
||||
self.dma_addr = CSRStorage(32, description = "Host Base address where to write/read data (i.e. SPARC Virtual addr)")
|
||||
#self.blk_cnt = CSRStorage(32, write_from_dev=True, description = "How many blk to read/write (max 2^{}-1); bit 31 is RD".format(max_block_bits), reset = 0)
|
||||
self.blk_cnt = CSRStorage(write_from_dev=True, fields = [CSRField("blk_cnt", max_block_bits, description = "How many blk to read/write (max 2^{}-1)".format(max_block_bits)),
|
||||
CSRField("rsvd", 32 - (max_block_bits + 1), description = "Reserved"),
|
||||
CSRField("rd_wr", 1, description = "Read/Write selector"),
|
||||
])
|
||||
self.last_blk = CSRStatus(32, description = "Last Blk addr finished on WB side")
|
||||
self.last_dma = CSRStatus(32, description = "Last DMA addr finished on WB side")
|
||||
self.dma_wrdone = CSRStatus(32, description = "DMA Block written to SDRAM", reset = 0)
|
||||
self.blk_rem = CSRStatus(32, description = "How many block remaining; bit 31 is RD", reset = 0)
|
||||
self.dma_status = CSRStatus(fields = [CSRField("rd_fsm_busy", 1, description = "Read FSM is doing some work"),
|
||||
CSRField("wr_fsm_busy", 1, description = "Write FSM is doing some work"),
|
||||
CSRField("has_wr_data", 1, description = "Data available to write to SDRAM"),
|
||||
CSRField("has_requests", 1, description = "There's outstanding requests to the SBus"),
|
||||
CSRField("has_rd_data", 1, description = "Data available to write to SBus"),
|
||||
])
|
||||
self.wr_tosdram = CSRStatus(32, description = "Last address written to SDRAM")
|
||||
|
||||
if (do_checksum):
|
||||
self.checksum = CSRStorage(data_width_bits, write_from_dev=True, description = "checksum (XOR)");
|
||||
|
||||
self.submodules.req_r_fsm = req_r_fsm = FSM(reset_state="Reset")
|
||||
self.submodules.req_w_fsm = req_w_fsm = FSM(reset_state="Reset")
|
||||
|
||||
self.comb += self.dma_status.fields.rd_fsm_busy.eq(~req_r_fsm.ongoing("Idle")) # Read FSM Busy
|
||||
self.comb += self.dma_status.fields.wr_fsm_busy.eq(~req_w_fsm.ongoing("Idle")) # Write FSM Busy
|
||||
self.comb += self.dma_status.fields.has_wr_data.eq(self.fromsbus_fifo.readable) # Some data available to write to memory
|
||||
|
||||
# The next two status bits reflect stats in the SBus clock domain
|
||||
self.submodules.fromsbus_req_fifo_readable_sync = BusSynchronizer(width = 1, idomain = "sbus", odomain = "sys")
|
||||
fromsbus_req_fifo_readable_in_sys = Signal()
|
||||
self.comb += self.fromsbus_req_fifo_readable_sync.i.eq(self.fromsbus_req_fifo.readable)
|
||||
self.comb += fromsbus_req_fifo_readable_in_sys.eq(self.fromsbus_req_fifo_readable_sync.o)
|
||||
|
||||
# w/o this extra delay, the driver sees an outdated checksum for some reason...
|
||||
# there's probably a more fundamental issue :-(
|
||||
# note: replaced PulseSynchronizer with BusSynchronizer, should I retry w/o this ?
|
||||
fromsbus_req_fifo_readable_in_sys_cnt = Signal(5)
|
||||
self.sync += If(fromsbus_req_fifo_readable_in_sys,
|
||||
fromsbus_req_fifo_readable_in_sys_cnt.eq(0x1F)
|
||||
).Else(
|
||||
If(fromsbus_req_fifo_readable_in_sys_cnt > 0,
|
||||
fromsbus_req_fifo_readable_in_sys_cnt.eq(fromsbus_req_fifo_readable_in_sys_cnt - 1)
|
||||
)
|
||||
)
|
||||
#self.comb += self.dma_status.fields.has_requests.eq(fromsbus_req_fifo_readable_in_sys) # we still have outstanding requests
|
||||
self.comb += self.dma_status.fields.has_requests.eq(fromsbus_req_fifo_readable_in_sys | (fromsbus_req_fifo_readable_in_sys_cnt != 0)) # we still have outstanding requests, or had recently
|
||||
|
||||
self.submodules.tosbus_fifo_readable_sync = BusSynchronizer(width = 1, idomain = "sbus", odomain = "sys")
|
||||
tosbus_fifo_readable_in_sys = Signal()
|
||||
self.comb += self.tosbus_fifo_readable_sync.i.eq(self.tosbus_fifo.readable)
|
||||
self.comb += tosbus_fifo_readable_in_sys.eq(self.tosbus_fifo_readable_sync.o)
|
||||
self.comb += self.dma_status.fields.has_rd_data.eq(tosbus_fifo_readable_in_sys) # there's still data to be sent to memory; this will drop before the last SBus Master Cycle is finished, but then the SBus is busy so the host won't be able to read the status before the cycle is finished so we're good
|
||||
|
||||
#self.comb += self.dma_status.status[16:17].eq(self.wishbone_w_master.cyc) # show the WB iface status (W)
|
||||
#self.comb += self.dma_status.status[17:18].eq(self.wishbone_w_master.stb)
|
||||
#self.comb += self.dma_status.status[18:19].eq(self.wishbone_w_master.we)
|
||||
#self.comb += self.dma_status.status[19:20].eq(self.wishbone_w_master.ack)
|
||||
#self.comb += self.dma_status.status[20:21].eq(self.wishbone_w_master.err)
|
||||
|
||||
#self.comb += self.dma_status.status[24:25].eq(self.wishbone_r_master.cyc) # show the WB iface status (R)
|
||||
#self.comb += self.dma_status.status[25:26].eq(self.wishbone_r_master.stb)
|
||||
#self.comb += self.dma_status.status[26:27].eq(self.wishbone_r_master.we)
|
||||
#self.comb += self.dma_status.status[27:28].eq(self.wishbone_r_master.ack)
|
||||
#self.comb += self.dma_status.status[28:29].eq(self.wishbone_r_master.err)
|
||||
|
||||
req_r_fsm.act("Reset",
|
||||
NextState("Idle")
|
||||
)
|
||||
req_r_fsm.act("Idle",
|
||||
If(((self.blk_cnt.fields.blk_cnt != 0) & # checking self.blk_cnt.re might be too transient ? -> need to auto-reset
|
||||
(~self.blk_cnt.fields.rd_wr)), # !read -> write
|
||||
NextValue(local_r_addr, self.blk_addr.storage),
|
||||
NextValue(dma_r_addr, self.dma_addr.storage),
|
||||
NextValue(self.blk_rem.status, Cat(self.blk_cnt.fields.blk_cnt, Signal(32-max_block_bits, reset = 0))),
|
||||
NextState("ReqFromMemory")
|
||||
).Elif(((self.blk_cnt.fields.blk_cnt != 0) & # checking self.blk_cnt.re might be too transient ? -> need to auto-reset
|
||||
(self.blk_cnt.fields.rd_wr)), # read
|
||||
NextValue(local_r_addr, self.blk_addr.storage),
|
||||
NextValue(dma_r_addr, self.dma_addr.storage),
|
||||
NextValue(self.blk_rem.status, Cat(self.blk_cnt.fields.blk_cnt, Signal(32-max_block_bits, reset = 0))),
|
||||
NextState("QueueReqToMemory")
|
||||
)
|
||||
)
|
||||
req_r_fsm.act("ReqFromMemory",
|
||||
self.dram_dma_reader.sink.address.eq(local_r_addr),
|
||||
self.dram_dma_reader.sink.valid.eq(1),
|
||||
If(self.dram_dma_reader.sink.ready,
|
||||
NextState("WaitForData")
|
||||
)
|
||||
)
|
||||
req_r_fsm.act("WaitForData",
|
||||
If(self.dram_dma_reader.source.valid & self.tosbus_fifo.writable,
|
||||
self.tosbus_fifo.we.eq(1),
|
||||
self.tosbus_fifo.din.eq(Cat(dma_r_addr, self.dram_dma_reader.source.data)),
|
||||
If(do_checksum,
|
||||
self.checksum.we.eq(1),
|
||||
self.checksum.dat_w.eq(self.checksum.storage ^ self.dram_dma_reader.source.data),
|
||||
),
|
||||
self.dram_dma_reader.source.ready.eq(1),
|
||||
NextValue(self.last_blk.status, local_r_addr),
|
||||
NextValue(self.last_dma.status, dma_r_addr),
|
||||
NextValue(self.blk_rem.status, self.blk_rem.status - 1),
|
||||
If(self.blk_rem.status[0:max_block_bits] <= 1,
|
||||
self.blk_cnt.we.eq(1), ## auto-reset
|
||||
self.blk_cnt.dat_w.eq(0),
|
||||
NextState("Idle"),
|
||||
).Else(
|
||||
NextValue(local_r_addr, local_r_addr + 1),
|
||||
NextValue(dma_r_addr, dma_r_addr + data_width),
|
||||
NextState("ReqFromMemory"),
|
||||
)
|
||||
)
|
||||
)
|
||||
req_r_fsm.act("QueueReqToMemory",
|
||||
If(self.fromsbus_req_fifo.writable,
|
||||
self.fromsbus_req_fifo.we.eq(1),
|
||||
self.fromsbus_req_fifo.din.eq(Cat(local_r_addr, dma_r_addr)),
|
||||
NextValue(self.last_blk.status, local_r_addr),
|
||||
NextValue(self.last_dma.status, dma_r_addr),
|
||||
NextValue(self.blk_rem.status, self.blk_rem.status - 1),
|
||||
If(self.blk_rem.status[0:max_block_bits] <= 1,
|
||||
self.blk_cnt.we.eq(1), ## auto-reset
|
||||
self.blk_cnt.dat_w.eq(0),
|
||||
NextState("Idle"),
|
||||
).Else(
|
||||
NextValue(local_r_addr, local_r_addr + 1),
|
||||
NextValue(dma_r_addr, dma_r_addr + data_width),
|
||||
NextValue(self.blk_rem.status, self.blk_rem.status - 1),
|
||||
NextState("QueueReqToMemory"), #redundant
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
# req_w_fsm.act("Reset",
|
||||
# NextState("Idle")
|
||||
# )
|
||||
# req_w_fsm.act("Idle",
|
||||
# If(self.fromsbus_fifo.readable &
|
||||
# ~self.wishbone_w_master.ack,
|
||||
# self.fromsbus_fifo.re.eq(1),
|
||||
# NextValue(self.wishbone_w_master.cyc, 1),
|
||||
# NextValue(self.wishbone_w_master.stb, 1),
|
||||
# NextValue(self.wishbone_w_master.sel, 2**len(self.wishbone_w_master.sel)-1),
|
||||
# NextValue(self.wishbone_w_master.we, 1),
|
||||
# NextValue(self.wishbone_w_master.adr, self.fromsbus_fifo.dout[0:blk_addr_width]),
|
||||
# NextValue(self.wishbone_w_master.dat_w, self.fromsbus_fifo.dout[blk_addr_width:(blk_addr_width + data_width_bits)]),
|
||||
# NextValue(self.wr_tosdram.status, self.fromsbus_fifo.dout[0:blk_addr_width]),
|
||||
# NextState("WaitForAck")
|
||||
# )
|
||||
# )
|
||||
# req_w_fsm.act("WaitForAck",
|
||||
# If(self.wishbone_w_master.ack,
|
||||
# NextValue(self.wishbone_w_master.cyc, 0),
|
||||
# NextValue(self.wishbone_w_master.stb, 0),
|
||||
# NextState("Idle"),
|
||||
# )
|
||||
# )
|
||||
|
||||
req_w_fsm.act("Reset",
|
||||
NextState("Idle")
|
||||
)
|
||||
req_w_fsm.act("Idle",
|
||||
If(self.fromsbus_fifo.readable,
|
||||
self.dram_dma_writer.sink.address.eq(self.fromsbus_fifo.dout[0:blk_addr_width]),
|
||||
self.dram_dma_writer.sink.data.eq(self.fromsbus_fifo.dout[blk_addr_width:(blk_addr_width + data_width_bits)]),
|
||||
self.dram_dma_writer.sink.valid.eq(1),
|
||||
NextValue(self.wr_tosdram.status, self.fromsbus_fifo.dout[0:blk_addr_width]),
|
||||
If(self.dram_dma_writer.sink.ready,
|
||||
self.fromsbus_fifo.re.eq(1),
|
||||
NextValue(self.dma_wrdone.status, self.dma_wrdone.status + 1),
|
||||
If(do_checksum,
|
||||
self.checksum.we.eq(1),
|
||||
self.checksum.dat_w.eq(self.checksum.storage ^ self.fromsbus_fifo.dout[blk_addr_width:(blk_addr_width + data_width_bits)]),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
133
sbus-to-ztex-gateware-migen/sbus_to_fpga_export.py
Normal file
133
sbus-to-ztex-gateware-migen/sbus_to_fpga_export.py
Normal file
@ -0,0 +1,133 @@
|
||||
import os
|
||||
import json
|
||||
import inspect
|
||||
from shutil import which
|
||||
from sysconfig import get_platform
|
||||
|
||||
from migen import *
|
||||
|
||||
from litex.soc.interconnect.csr import CSRStatus
|
||||
|
||||
from litex.build.tools import generated_banner
|
||||
|
||||
from litex.soc.doc.rst import reflow
|
||||
from litex.soc.doc.module import gather_submodules, ModuleNotDocumented, DocumentedModule, DocumentedInterrupts
|
||||
from litex.soc.doc.csr import DocumentedCSRRegion
|
||||
from litex.soc.interconnect.csr import _CompoundCSR
|
||||
|
||||
# for generating a timestamp in the description field, if none is otherwise given
|
||||
import datetime
|
||||
import time
|
||||
|
||||
def _get_rw_functions_c(name, csr_name, reg_base, area_base, nwords, busword, alignment, read_only, with_access_functions):
|
||||
reg_name = name + "_" + csr_name
|
||||
r = ""
|
||||
|
||||
addr_str = "CSR_{}_ADDR".format(reg_name.upper())
|
||||
size_str = "CSR_{}_SIZE".format(reg_name.upper())
|
||||
r += "#define {} (CSR_{}_BASE + {}L)\n".format(addr_str, name.upper(), hex(reg_base - area_base))
|
||||
r += "#define {} {}\n".format(size_str, nwords)
|
||||
|
||||
size = nwords*busword//8
|
||||
if size > 8:
|
||||
# downstream should select appropriate `csr_[rd|wr]_buf_uintX()` pair!
|
||||
return r
|
||||
elif size > 4:
|
||||
ctype = "uint64_t"
|
||||
elif size > 2:
|
||||
ctype = "uint32_t"
|
||||
elif size > 1:
|
||||
ctype = "uint16_t"
|
||||
else:
|
||||
ctype = "uint8_t"
|
||||
|
||||
stride = alignment//8;
|
||||
if with_access_functions:
|
||||
r += "static inline {} {}_read(struct sbusfpga_{}_softc *sc) {{\n".format(ctype, reg_name, name)
|
||||
if nwords > 1:
|
||||
r += "\t{} r = bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_{}, {}L);\n".format(ctype, name, hex(reg_base - area_base))
|
||||
for sub in range(1, nwords):
|
||||
r += "\tr <<= {};\n".format(busword)
|
||||
r += "\tr |= bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_{}, {}L);\n".format(name, hex(reg_base - area_base + sub*stride))
|
||||
r += "\treturn r;\n}\n"
|
||||
else:
|
||||
r += "\treturn bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_{}, {}L);\n}}\n".format(name, hex(reg_base - area_base))
|
||||
|
||||
if not read_only:
|
||||
r += "static inline void {}_write(struct sbusfpga_{}_softc *sc, {} v) {{\n".format(reg_name, name, ctype)
|
||||
for sub in range(nwords):
|
||||
shift = (nwords-sub-1)*busword
|
||||
if shift:
|
||||
v_shift = "v >> {}".format(shift)
|
||||
else:
|
||||
v_shift = "v"
|
||||
r += "\tbus_space_write_4(sc->sc_bustag, sc->sc_bhregs_{}, {}L, {});\n".format(name, hex(reg_base - area_base + sub*stride), v_shift)
|
||||
r += "}\n"
|
||||
return r
|
||||
|
||||
|
||||
def get_csr_header(regions, constants, csr_base=None, with_access_functions=True):
|
||||
alignment = constants.get("CONFIG_CSR_ALIGNMENT", 32)
|
||||
r = generated_banner("//")
|
||||
#if with_access_functions: # FIXME
|
||||
# r += "#include <generated/soc.h>\n"
|
||||
r += "#ifndef __GENERATED_CSR_H\n#define __GENERATED_CSR_H\n"
|
||||
#if with_access_functions:
|
||||
# r += "#include <stdint.h>\n"
|
||||
# r += "#include <system.h>\n"
|
||||
# r += "#ifndef CSR_ACCESSORS_DEFINED\n"
|
||||
# r += "#include <hw/common.h>\n"
|
||||
# r += "#endif /* ! CSR_ACCESSORS_DEFINED */\n"
|
||||
csr_base = csr_base if csr_base is not None else regions[next(iter(regions))].origin
|
||||
r += "#ifndef CSR_BASE\n"
|
||||
r += "#define CSR_BASE {}L\n".format(hex(csr_base))
|
||||
r += "#endif\n"
|
||||
for name, region in regions.items():
|
||||
origin = region.origin - csr_base
|
||||
r += "\n/* "+name+" */\n"
|
||||
r += "#ifndef CSR_"+name.upper()+"_BASE\n"
|
||||
r += "#define CSR_"+name.upper()+"_BASE (CSR_BASE + "+hex(origin)+"L)\n"
|
||||
if not isinstance(region.obj, Memory):
|
||||
for csr in region.obj:
|
||||
nr = (csr.size + region.busword - 1)//region.busword
|
||||
r += _get_rw_functions_c(name, csr.name, origin, region.origin - csr_base, nr, region.busword, alignment,
|
||||
getattr(csr, "read_only", False), with_access_functions)
|
||||
origin += alignment//8*nr
|
||||
if hasattr(csr, "fields"):
|
||||
for field in csr.fields.fields:
|
||||
offset = str(field.offset)
|
||||
size = str(field.size)
|
||||
r += "#define CSR_"+name.upper()+"_"+csr.name.upper()+"_"+field.name.upper()+"_OFFSET "+offset+"\n"
|
||||
r += "#define CSR_"+name.upper()+"_"+csr.name.upper()+"_"+field.name.upper()+"_SIZE "+size+"\n"
|
||||
if with_access_functions and csr.size <= 32: # FIXME: Implement extract/read functions for csr.size > 32-bit.
|
||||
reg_name = name + "_" + csr.name.lower()
|
||||
field_name = reg_name + "_" + field.name.lower()
|
||||
r += "static inline uint32_t " + field_name + "_extract(struct sbusfpga_" + name + "_softc *sc, uint32_t oldword) {\n"
|
||||
r += "\tuint32_t mask = ((1 << " + size + ")-1);\n"
|
||||
r += "\treturn ( (oldword >> " + offset + ") & mask );\n}\n"
|
||||
r += "static inline uint32_t " + field_name + "_read(struct sbusfpga_" + name + "_softc *sc) {\n"
|
||||
r += "\tuint32_t word = " + reg_name + "_read(sc);\n"
|
||||
r += "\treturn " + field_name + "_extract(sc, word);\n"
|
||||
r += "}\n"
|
||||
if not getattr(csr, "read_only", False):
|
||||
r += "static inline uint32_t " + field_name + "_replace(struct sbusfpga_" + name + "_softc *sc, uint32_t oldword, uint32_t plain_value) {\n"
|
||||
r += "\tuint32_t mask = ((1 << " + size + ")-1);\n"
|
||||
r += "\treturn (oldword & (~(mask << " + offset + "))) | (mask & plain_value)<< " + offset + " ;\n}\n"
|
||||
r += "static inline void " + field_name + "_write(struct sbusfpga_" + name + "_softc *sc, uint32_t plain_value) {\n"
|
||||
r += "\tuint32_t oldword = " + reg_name + "_read(sc);\n"
|
||||
r += "\tuint32_t newword = " + field_name + "_replace(sc, oldword, plain_value);\n"
|
||||
r += "\t" + reg_name + "_write(sc, newword);\n"
|
||||
r += "}\n"
|
||||
r += "#endif // CSR_"+name.upper()+"_BASE\n"
|
||||
|
||||
r += "\n#endif\n"
|
||||
return r
|
||||
|
||||
|
||||
def get_csr_forth_header(csr_regions, mem_regions, constants, csr_base=None):
|
||||
r = "\\ auto-generated base regions for CSRs in the PROM\n"
|
||||
for name, region in csr_regions.items():
|
||||
r += "h# " + hex(region.origin).replace("0x", "") + " constant " + "sbusfpga_csraddr_{}".format(name) + "\n"
|
||||
for name, region in mem_regions.items():
|
||||
r += "h# " + hex(region.origin).replace("0x", "") + " constant " + "sbusfpga_regionaddr_{}".format(name) + "\n"
|
||||
return r
|
||||
1829
sbus-to-ztex-gateware-migen/sbus_to_fpga_fsm.py
Normal file
1829
sbus-to-ztex-gateware-migen/sbus_to_fpga_fsm.py
Normal file
File diff suppressed because it is too large
Load Diff
59
sbus-to-ztex-gateware-migen/sbus_to_fpga_fsmstat.py
Normal file
59
sbus-to-ztex-gateware-migen/sbus_to_fpga_fsmstat.py
Normal file
@ -0,0 +1,59 @@
|
||||
from migen import *
|
||||
from migen.genlib.cdc import BusSynchronizer
|
||||
from litex.soc.interconnect.csr import *
|
||||
from litex.soc.interconnect import wishbone
|
||||
|
||||
class SBusFPGABusStat(Module, AutoCSR):
|
||||
def __init__(self, sbus_bus):
|
||||
self.stat_ctrl = CSRStorage(fields = [CSRField("update", 1, description = "update")])
|
||||
self.submodules.sync_update = BusSynchronizer(width = 1, idomain="sys", odomain="sbus")
|
||||
self.comb += self.sync_update.i.eq(self.stat_ctrl.fields.update)
|
||||
self.comb += sbus_bus.stat_update.eq(self.sync_update.o)
|
||||
|
||||
self.live_stat_cycle_counter = CSRStatus(32, description="live_stat_cycle_counter")
|
||||
self.stat_cycle_counter = CSRStatus(32, description="stat_cycle_counter")
|
||||
self.stat_slave_start_counter = CSRStatus(32, description="stat_slave_start_counter")
|
||||
self.stat_slave_done_counter = CSRStatus(32, description="stat_slave_done_counter")
|
||||
self.stat_slave_rerun_counter = CSRStatus(32, description="stat_slave_rerun_counter")
|
||||
self.stat_slave_early_error_counter = CSRStatus(32, description="stat_slave_early_error_counter")
|
||||
self.stat_master_start_counter = CSRStatus(32, description="stat_master_start_counter")
|
||||
self.stat_master_done_counter = CSRStatus(32, description="stat_master_done_counter")
|
||||
self.stat_master_error_counter = CSRStatus(32, description="stat_master_error_counter")
|
||||
self.stat_master_rerun_counter = CSRStatus(32, description="stat_master_rerun_counter")
|
||||
self.sbus_master_error_virtual = CSRStatus(32, description="sbus_master_error_virtual")
|
||||
|
||||
self.submodules.sync_live_stat_cycle_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys")
|
||||
self.comb += self.sync_live_stat_cycle_counter.i.eq(sbus_bus.stat_cycle_counter)
|
||||
self.comb += self.live_stat_cycle_counter.status.eq(self.sync_live_stat_cycle_counter.o)
|
||||
|
||||
self.submodules.sync_stat_cycle_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys")
|
||||
self.comb += self.sync_stat_cycle_counter.i.eq(sbus_bus.buf_stat_cycle_counter)
|
||||
self.comb += self.stat_cycle_counter.status.eq(self.sync_stat_cycle_counter.o)
|
||||
|
||||
self.submodules.sync_stat_slave_start_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys");
|
||||
self.comb += self.sync_stat_slave_start_counter.i.eq(sbus_bus.buf_stat_slave_start_counter)
|
||||
self.comb += self.stat_slave_start_counter.status.eq(self.sync_stat_slave_start_counter.o)
|
||||
self.submodules.sync_stat_slave_done_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys");
|
||||
self.comb += self.sync_stat_slave_done_counter.i.eq(sbus_bus.buf_stat_slave_done_counter)
|
||||
self.comb += self.stat_slave_done_counter.status.eq(self.sync_stat_slave_done_counter.o)
|
||||
self.submodules.sync_stat_slave_rerun_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys");
|
||||
self.comb += self.sync_stat_slave_rerun_counter.i.eq(sbus_bus.buf_stat_slave_rerun_counter)
|
||||
self.comb += self.stat_slave_rerun_counter.status.eq(self.sync_stat_slave_rerun_counter.o)
|
||||
self.submodules.sync_stat_slave_early_error_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys");
|
||||
self.comb += self.sync_stat_slave_early_error_counter.i.eq(sbus_bus.buf_stat_slave_early_error_counter)
|
||||
self.comb += self.stat_slave_early_error_counter.status.eq(self.sync_stat_slave_early_error_counter.o)
|
||||
self.submodules.sync_stat_master_start_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys");
|
||||
self.comb += self.sync_stat_master_start_counter.i.eq(sbus_bus.buf_stat_master_start_counter)
|
||||
self.comb += self.stat_master_start_counter.status.eq(self.sync_stat_master_start_counter.o)
|
||||
self.submodules.sync_stat_master_done_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys");
|
||||
self.comb += self.sync_stat_master_done_counter.i.eq(sbus_bus.buf_stat_master_done_counter)
|
||||
self.comb += self.stat_master_done_counter.status.eq(self.sync_stat_master_done_counter.o)
|
||||
self.submodules.sync_stat_master_error_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys");
|
||||
self.comb += self.sync_stat_master_error_counter.i.eq(sbus_bus.buf_stat_master_error_counter)
|
||||
self.comb += self.stat_master_error_counter.status.eq(self.sync_stat_master_error_counter.o)
|
||||
self.submodules.sync_stat_master_rerun_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys");
|
||||
self.comb += self.sync_stat_master_rerun_counter.i.eq(sbus_bus.buf_stat_master_rerun_counter)
|
||||
self.comb += self.stat_master_rerun_counter.status.eq(self.sync_stat_master_rerun_counter.o)
|
||||
self.submodules.sync_sbus_master_error_virtual = BusSynchronizer(width = 32, idomain="sbus", odomain="sys");
|
||||
self.comb += self.sync_sbus_master_error_virtual.i.eq(sbus_bus.buf_sbus_master_error_virtual)
|
||||
self.comb += self.sbus_master_error_virtual.status.eq(self.sync_sbus_master_error_virtual.o)
|
||||
350
sbus-to-ztex-gateware-migen/sbus_to_fpga_soc.py
Normal file
350
sbus-to-ztex-gateware-migen/sbus_to_fpga_soc.py
Normal file
@ -0,0 +1,350 @@
|
||||
import os
|
||||
import argparse
|
||||
from migen import *
|
||||
import litex
|
||||
from litex.build.generic_platform import *
|
||||
from litex.build.xilinx.vivado import vivado_build_args, vivado_build_argdict
|
||||
from litex.soc.integration.soc import *
|
||||
from litex.soc.integration.soc_core import *
|
||||
from litex.soc.integration.builder import *
|
||||
from litex.soc.interconnect import wishbone
|
||||
from litex.soc.cores.clock import *
|
||||
from litex.soc.cores.led import LedChaser
|
||||
import ztex213_sbus
|
||||
from migen.genlib.fifo import *
|
||||
|
||||
from litedram.modules import MT41J128M16
|
||||
from litedram.phy import s7ddrphy
|
||||
|
||||
from sbus_to_fpga_fsm import *
|
||||
from sbus_to_fpga_fsmstat import *
|
||||
from sbus_to_fpga_blk_dma import *
|
||||
from sbus_to_fpga_trng import *
|
||||
|
||||
from litedram.frontend.dma import *
|
||||
|
||||
from engine import Engine;
|
||||
from migen.genlib.cdc import BusSynchronizer
|
||||
from migen.genlib.resetsync import AsyncResetSynchronizer;
|
||||
|
||||
import sbus_to_fpga_export;
|
||||
|
||||
# CRG ----------------------------------------------------------------------------------------------
|
||||
|
||||
class _CRG(Module):
|
||||
def __init__(self, platform, sys_clk_freq, usb=True):
|
||||
self.clock_domains.cd_sys = ClockDomain() # 100 MHz PLL, reset'ed by SBus (via pll), SoC/Wishbone main clock
|
||||
self.clock_domains.cd_sys4x = ClockDomain(reset_less=True)
|
||||
self.clock_domains.cd_sys4x_dqs = ClockDomain(reset_less=True)
|
||||
self.clock_domains.cd_idelay = ClockDomain()
|
||||
## self.clock_domains.cd_sys = ClockDomain() # 16.67-25 MHz SBus, reset'ed by SBus, native SBus & SYS clock domain
|
||||
self.clock_domains.cd_native = ClockDomain(reset_less=True) # 48MHz native, non-reset'ed (for power-on long delay, never reset, we don't want the delay after a warm reset)
|
||||
self.clock_domains.cd_sbus = ClockDomain() # 16.67-25 MHz SBus, reset'ed by SBus, native SBus clock domain
|
||||
# self.clock_domains.cd_por = ClockDomain() # 48 MHz native, reset'ed by SBus, power-on-reset timer
|
||||
if (usb):
|
||||
self.clock_domains.cd_usb = ClockDomain() # 48 MHZ PLL, reset'ed by SBus (via pll), for USB controller
|
||||
self.clock_domains.cd_clk50 = ClockDomain() # 50 MHz (gated) for curve25519engine -> eng_clk
|
||||
#self.clock_domains.cd_clk100 = ClockDomain() # 100 MHz for curve25519engine -> sys_clk
|
||||
self.clock_domains.cd_clk100_gated = ClockDomain() # 100 MHz (gated) for curve25519engine -> mul_clk
|
||||
self.clock_domains.cd_clk200 = ClockDomain() # 200 MHz (gated) for curve25519engine -> rf_clk
|
||||
|
||||
# # #
|
||||
clk48 = platform.request("clk48")
|
||||
###### explanations from betrusted-io/betrusted-soc/betrusted_soc.py
|
||||
# Note: below feature cannot be used because Litex appends this *after* platform commands! This causes the generated
|
||||
# clock derived constraints immediately below to fail, because .xdc file is parsed in-order, and the main clock needs
|
||||
# to be created before the derived clocks. Instead, we use the line afterwards.
|
||||
platform.add_platform_command("create_clock -name clk48 -period 20.8333 [get_nets clk48]")
|
||||
# The above constraint must strictly proceed the below create_generated_clock constraints in the .XDC file
|
||||
# This allows PLLs/MMCMEs to be placed anywhere and reference the input clock
|
||||
self.clk48_bufg = Signal()
|
||||
self.specials += Instance("BUFG", i_I=clk48, o_O=self.clk48_bufg)
|
||||
self.comb += self.cd_native.clk.eq(self.clk48_bufg)
|
||||
#self.cd_native.clk = clk48
|
||||
|
||||
clk_sbus = platform.request("SBUS_3V3_CLK")
|
||||
self.cd_sbus.clk = clk_sbus
|
||||
rst_sbus = platform.request("SBUS_3V3_RSTs")
|
||||
self.comb += self.cd_sbus.rst.eq(~rst_sbus)
|
||||
##self.cd_sys.clk = clk_sbus
|
||||
##self.comb += self.cd_sys.rst.eq(~rst_sbus)
|
||||
|
||||
self.curve25519_on = Signal()
|
||||
|
||||
self.submodules.pll = pll = S7MMCM(speedgrade=-1)
|
||||
#pll.register_clkin(clk48, 48e6)
|
||||
pll.register_clkin(self.clk48_bufg, 48e6)
|
||||
pll.create_clkout(self.cd_sys, sys_clk_freq, gated_replicas={self.cd_clk100_gated : pll.locked & self.curve25519_on})
|
||||
platform.add_platform_command("create_generated_clock -name sysclk [get_pins {{MMCME2_ADV/CLKOUT0}}]")
|
||||
pll.create_clkout(self.cd_sys4x, 4*sys_clk_freq)
|
||||
platform.add_platform_command("create_generated_clock -name sys4xclk [get_pins {{MMCME2_ADV/CLKOUT1}}]")
|
||||
pll.create_clkout(self.cd_sys4x_dqs, 4*sys_clk_freq, phase=90)
|
||||
platform.add_platform_command("create_generated_clock -name sys4x90clk [get_pins {{MMCME2_ADV/CLKOUT2}}]")
|
||||
self.comb += pll.reset.eq(~rst_sbus) # | ~por_done
|
||||
platform.add_false_path_constraints(self.cd_native.clk, self.cd_sbus.clk)
|
||||
platform.add_false_path_constraints(self.cd_sbus.clk, self.cd_native.clk)
|
||||
#platform.add_false_path_constraints(self.cd_sys.clk, self.cd_sbus.clk)
|
||||
#platform.add_false_path_constraints(self.cd_sbus.clk, self.cd_sys.clk)
|
||||
##platform.add_false_path_constraints(self.cd_native.clk, self.cd_sys.clk)
|
||||
|
||||
pll.create_clkout(self.cd_clk50, sys_clk_freq/2, ce=pll.locked & self.curve25519_on)
|
||||
platform.add_platform_command("create_generated_clock -name clk50 [get_pins {{MMCME2_ADV/CLKOUT3}}]")
|
||||
pll.create_clkout(self.cd_clk200, sys_clk_freq*2, ce=pll.locked & self.curve25519_on)
|
||||
platform.add_platform_command("create_generated_clock -name clk200 [get_pins {{MMCME2_ADV/CLKOUT4}}]")
|
||||
|
||||
#self.submodules.curve25519_pll = curve25519_pll = S7MMCM(speedgrade=-1)
|
||||
#curve25519_clk_freq = 90e6
|
||||
##self.curve25519_on = Signal()
|
||||
##curve25519_pll.register_clkin(clk48, 48e6)
|
||||
#curve25519_pll.register_clkin(self.clk48_bufg, 48e6)
|
||||
#curve25519_pll.create_clkout(self.cd_clk50, curve25519_clk_freq/2, margin=0, ce=curve25519_pll.locked & self.curve25519_on)
|
||||
#platform.add_platform_command("create_generated_clock -name clk50 [get_pins {{MMCME2_ADV_1/CLKOUT0}}]")
|
||||
#curve25519_pll.create_clkout(self.cd_clk100, curve25519_clk_freq, margin=0, ce=curve25519_pll.locked,
|
||||
# gated_replicas={self.cd_clk100_gated : curve25519_pll.locked & self.curve25519_on})
|
||||
#platform.add_platform_command("create_generated_clock -name clk100 [get_pins {{MMCME2_ADV_1/CLKOUT1}}]")
|
||||
#curve25519_pll.create_clkout(self.cd_clk200, curve25519_clk_freq*2, margin=0, ce=curve25519_pll.locked & self.curve25519_on)
|
||||
#platform.add_platform_command("create_generated_clock -name clk200 [get_pins {{MMCME2_ADV_1/CLKOUT2}}]")
|
||||
##self.comb += curve25519_pll.reset.eq(~rst_sbus) # | ~por_done
|
||||
#platform.add_false_path_constraints(self.cd_sys.clk, self.cd_clk50.clk)
|
||||
#platform.add_false_path_constraints(self.cd_sys.clk, self.cd_clk100.clk)
|
||||
#platform.add_false_path_constraints(self.cd_sys.clk, self.cd_clk200.clk)
|
||||
#platform.add_false_path_constraints(self.cd_clk50.clk, self.cd_sys.clk)
|
||||
#platform.add_false_path_constraints(self.cd_clk100.clk, self.cd_sys.clk)
|
||||
#platform.add_false_path_constraints(self.cd_clk200.clk, self.cd_sys.clk)
|
||||
|
||||
# Power on reset, reset propagate from SBus to SYS
|
||||
# por_count = Signal(16, reset=2**16-1)
|
||||
# por_done = Signal()
|
||||
# self.comb += self.cd_por.clk.eq(clk48)
|
||||
# self.comb += por_done.eq(por_count == 0)
|
||||
# self.sync.por += If(~por_done, por_count.eq(por_count - 1))
|
||||
# self.comb += self.cd_por.rst.eq(~rst_sbus)
|
||||
# self.comb += pll.reset.eq(~por_done | ~rst_sbus)
|
||||
|
||||
# USB
|
||||
if (usb):
|
||||
self.submodules.usb_pll = usb_pll = S7MMCM(speedgrade=-1)
|
||||
#usb_pll.register_clkin(clk48, 48e6)
|
||||
usb_pll.register_clkin(self.clk48_bufg, 48e6)
|
||||
usb_pll.create_clkout(self.cd_usb, 48e6, margin = 0)
|
||||
platform.add_platform_command("create_generated_clock -name usbclk [get_pins {{MMCME2_ADV_2/CLKOUT0}}]")
|
||||
self.comb += usb_pll.reset.eq(~rst_sbus) # | ~por_done
|
||||
platform.add_false_path_constraints(self.cd_sys.clk, self.cd_usb.clk)
|
||||
|
||||
self.submodules.pll_idelay = pll_idelay = S7MMCM(speedgrade=-1)
|
||||
#pll_idelay.register_clkin(clk48, 48e6)
|
||||
pll_idelay.register_clkin(self.clk48_bufg, 48e6)
|
||||
pll_idelay.create_clkout(self.cd_idelay, 200e6, margin = 0)
|
||||
platform.add_platform_command("create_generated_clock -name idelayclk [get_pins {{MMCME2_ADV_3/CLKOUT0}}]")
|
||||
self.comb += pll_idelay.reset.eq(~rst_sbus) # | ~por_done
|
||||
|
||||
self.submodules.idelayctrl = S7IDELAYCTRL(self.cd_idelay)
|
||||
|
||||
class SBusFPGA(SoCCore):
|
||||
def __init__(self, version, usb, **kwargs):
|
||||
print(f"Building SBusFPGA for board version {version}")
|
||||
|
||||
kwargs["cpu_type"] = "None"
|
||||
kwargs["integrated_sram_size"] = 0
|
||||
kwargs["with_uart"] = False
|
||||
kwargs["with_timer"] = False
|
||||
|
||||
self.sys_clk_freq = sys_clk_freq = 100e6 ## 25e6
|
||||
|
||||
self.platform = platform = ztex213_sbus.Platform(variant="ztex2.13a", version = version)
|
||||
|
||||
if (version == "V1.0"):
|
||||
self.platform.add_extension(ztex213_sbus._usb_io_v1_0)
|
||||
|
||||
SoCCore.__init__(self,
|
||||
platform=platform,
|
||||
sys_clk_freq=sys_clk_freq,
|
||||
clk_freq=sys_clk_freq,
|
||||
csr_paging=0x1000, # default is 0x800
|
||||
**kwargs)
|
||||
|
||||
# This mem-map is also exposed in the FSM (matched prefixes)
|
||||
# and in the PROM (to tell NetBSD where everything is)
|
||||
# Currently it is a straight mapping between the two:
|
||||
# the physical address here are used as offset in the SBus
|
||||
# reserved area of 256 MiB
|
||||
# Anything at 0x10000000 is therefore unreachable directly
|
||||
# The position of the 'usb_fake_dma' is so it overlaps
|
||||
# the virtual address space used by NetBSD DMA allocators
|
||||
# (themselves constrained by the SBus MMU capabilities)
|
||||
self.wb_mem_map = wb_mem_map = {
|
||||
"prom": 0x00000000,
|
||||
"csr" : 0x00040000,
|
||||
"usb_host": 0x00080000,
|
||||
"usb_shared_mem": 0x00090000, # unused
|
||||
"curve25519engine": 0x000a0000,
|
||||
"main_ram": 0x80000000,
|
||||
"usb_fake_dma": 0xfc000000,
|
||||
}
|
||||
self.mem_map.update(wb_mem_map)
|
||||
self.submodules.crg = _CRG(platform=platform, sys_clk_freq=sys_clk_freq, usb=usb)
|
||||
self.platform.add_period_constraint(self.platform.lookup_request("SBUS_3V3_CLK", loose=True), 1e9/25e6) # SBus max
|
||||
|
||||
if (version == "V1.0"):
|
||||
self.submodules.leds = LedChaser(
|
||||
pads = platform.request("SBUS_DATA_OE_LED_2"), #platform.request("user_led", 7),
|
||||
sys_clk_freq = sys_clk_freq)
|
||||
self.add_csr("leds")
|
||||
|
||||
if (usb):
|
||||
self.add_usb_host(pads=platform.request("usb"), usb_clk_freq=48e6)
|
||||
if (version == "V1.0"):
|
||||
pad_usb_interrupt = platform.request("SBUS_3V3_INT1s") ## only one usable
|
||||
elif (version == "V1.2"):
|
||||
pad_usb_interrupt = platform.request("SBUS_3V3_INT3s") ## can be 1-6, beware others
|
||||
sig_usb_interrupt = Signal(reset=1)
|
||||
# the 74LVC2G07 takes care of the Z state: 1 -> Z on the bus, 0 -> 0 on the bus (asserted interrupt)
|
||||
self.comb += pad_usb_interrupt.eq(sig_usb_interrupt)
|
||||
self.comb += sig_usb_interrupt.eq(~self.usb_host.interrupt) ##
|
||||
|
||||
|
||||
#pad_SBUS_DATA_OE_LED = platform.request("SBUS_DATA_OE_LED")
|
||||
#SBUS_DATA_OE_LED_o = Signal()
|
||||
#self.comb += pad_SBUS_DATA_OE_LED.eq(SBUS_DATA_OE_LED_o)
|
||||
#pad_SBUS_DATA_OE_LED_2 = platform.request("SBUS_DATA_OE_LED_2")
|
||||
#SBUS_DATA_OE_LED_2_o = Signal()
|
||||
#self.comb += pad_SBUS_DATA_OE_LED_2.eq(SBUS_DATA_OE_LED_2_o)
|
||||
#self.comb += SBUS_DATA_OE_LED_o.eq(~SBUS_3V3_INT1s_o)
|
||||
|
||||
prom_file = "prom_migen.fc"
|
||||
prom_data = soc_core.get_mem_data(prom_file, "big")
|
||||
# prom = Array(prom_data)
|
||||
#print("\n****************************************\n")
|
||||
#for i in range(len(prom)):
|
||||
# print(hex(prom[i]))
|
||||
#print("\n****************************************\n")
|
||||
self.add_ram("prom", origin=self.mem_map["prom"], size=2**16, contents=prom_data, mode="r")
|
||||
#getattr(self,"prom").mem.init = prom_data
|
||||
#getattr(self,"prom").mem.depth = 2**14
|
||||
|
||||
self.submodules.ddrphy = s7ddrphy.A7DDRPHY(platform.request("ddram"),
|
||||
memtype = "DDR3",
|
||||
nphases = 4,
|
||||
sys_clk_freq = sys_clk_freq)
|
||||
self.add_sdram("sdram",
|
||||
phy = self.ddrphy,
|
||||
module = MT41J128M16(sys_clk_freq, "1:4"),
|
||||
l2_cache_size = 0,
|
||||
)
|
||||
# don't enable anything on the SBus side for 20 seconds after power up
|
||||
# this avoids FPGA initialization messing with the cold boot process
|
||||
# requires us to reset the SPARCstation afterward so the FPGA board
|
||||
# is properly identified
|
||||
# This is in the 'native' ClockDomain that is never reset
|
||||
hold_reset_ctr = Signal(30, reset=960000000)
|
||||
self.sync.native += If(hold_reset_ctr>0, hold_reset_ctr.eq(hold_reset_ctr - 1))
|
||||
hold_reset = Signal(reset=1)
|
||||
self.comb += hold_reset.eq(~(hold_reset_ctr == 0))
|
||||
|
||||
# Interface SBus to wishbone
|
||||
# we need to cross clock domains
|
||||
wishbone_slave_sbus = wishbone.Interface(data_width=self.bus.data_width)
|
||||
wishbone_master_sys = wishbone.Interface(data_width=self.bus.data_width)
|
||||
self.submodules.wishbone_master_sbus = wishbone.WishboneDomainCrossingMaster(platform=self.platform, slave=wishbone_master_sys, cd_master="sbus", cd_slave="sys")
|
||||
self.submodules.wishbone_slave_sys = wishbone.WishboneDomainCrossingMaster(platform=self.platform, slave=wishbone_slave_sbus, cd_master="sys", cd_slave="sbus")
|
||||
|
||||
# SPARCstation 20 slave interface to the main memory are limited to 32-bytes burst (32-bits wide, 8 word long)
|
||||
# burst_size=16 should work on Ultra systems, but then they probably should go for 64-bits ET as well...
|
||||
# Older systems are probably limited to burst_size=4, (it should always be available)
|
||||
burst_size=8
|
||||
self.submodules.tosbus_fifo = ClockDomainsRenamer({"read": "sbus", "write": "sys"})(AsyncFIFOBuffered(width=(32+burst_size*32), depth=burst_size))
|
||||
self.submodules.fromsbus_fifo = ClockDomainsRenamer({"write": "sbus", "read": "sys"})(AsyncFIFOBuffered(width=((30-log2_int(burst_size))+burst_size*32), depth=burst_size))
|
||||
self.submodules.fromsbus_req_fifo = ClockDomainsRenamer({"read": "sbus", "write": "sys"})(AsyncFIFOBuffered(width=((30-log2_int(burst_size))+32), depth=burst_size))
|
||||
|
||||
self.submodules.dram_dma_writer = LiteDRAMDMAWriter(port=self.sdram.crossbar.get_port(mode="write", data_width=burst_size*32),
|
||||
fifo_depth=4,
|
||||
fifo_buffered=True)
|
||||
|
||||
self.submodules.dram_dma_reader = LiteDRAMDMAReader(port=self.sdram.crossbar.get_port(mode="read", data_width=burst_size*32),
|
||||
fifo_depth=4,
|
||||
fifo_buffered=True)
|
||||
|
||||
self.submodules.exchange_with_mem = ExchangeWithMem(soc=self,
|
||||
tosbus_fifo=self.tosbus_fifo,
|
||||
fromsbus_fifo=self.fromsbus_fifo,
|
||||
fromsbus_req_fifo=self.fromsbus_req_fifo,
|
||||
dram_dma_writer=self.dram_dma_writer,
|
||||
dram_dma_reader=self.dram_dma_reader,
|
||||
burst_size=burst_size,
|
||||
do_checksum = True)
|
||||
|
||||
_sbus_bus = SBusFPGABus(platform=self.platform,
|
||||
hold_reset=hold_reset,
|
||||
wishbone_slave=wishbone_slave_sbus,
|
||||
wishbone_master=self.wishbone_master_sbus,
|
||||
tosbus_fifo=self.tosbus_fifo,
|
||||
fromsbus_fifo=self.fromsbus_fifo,
|
||||
fromsbus_req_fifo=self.fromsbus_req_fifo,
|
||||
burst_size=burst_size)
|
||||
#self.submodules.sbus_bus = _sbus_bus
|
||||
self.submodules.sbus_bus = ClockDomainsRenamer("sbus")(_sbus_bus)
|
||||
self.submodules.sbus_bus_stat = SBusFPGABusStat(sbus_bus = self.sbus_bus)
|
||||
|
||||
self.bus.add_master(name="SBusBridgeToWishbone", master=wishbone_master_sys)
|
||||
|
||||
if (usb):
|
||||
self.bus.add_slave(name="usb_fake_dma", slave=self.wishbone_slave_sys, region=SoCRegion(origin=self.mem_map.get("usb_fake_dma", None), size=0x03ffffff, cached=False))
|
||||
#self.bus.add_master(name="mem_read_master", master=self.exchange_with_mem.wishbone_r_slave)
|
||||
#self.bus.add_master(name="mem_write_master", master=self.exchange_with_mem.wishbone_w_slave)
|
||||
|
||||
#self.add_sdcard()
|
||||
|
||||
self.submodules.trng = NeoRV32TrngWrapper(platform=platform)
|
||||
|
||||
# beware the naming, as 'clk50' 'sysclk' 'clk200' are used in the original platform constraints
|
||||
# the local engine.py was slightly modified to have configurable names, so we can have 'clk50', 'clk100', 'clk200'
|
||||
# Beware that Engine implicitely runs in 'sys' by default, need to rename that one as well
|
||||
# Actually renaming 'sys' doesn't work - unless we can CDC the CSRs as well
|
||||
self.submodules.curve25519engine = ClockDomainsRenamer({"eng_clk":"clk50", "rf_clk":"clk200", "mul_clk":"clk100_gated"})(Engine(platform=platform,prefix=self.mem_map.get("curve25519engine", None))) # , "sys":"clk100"
|
||||
#self.submodules.curve25519engine_wishbone_cdc = wishbone.WishboneDomainCrossingMaster(platform=self.platform, slave=self.curve25519engine.bus, cd_master="sys", cd_slave="clk100")
|
||||
#self.bus.add_slave("curve25519engine", self.curve25519engine_wishbone_cdc, SoCRegion(origin=self.mem_map.get("curve25519engine", None), size=0x20000, cached=False))
|
||||
self.bus.add_slave("curve25519engine", self.curve25519engine.bus, SoCRegion(origin=self.mem_map.get("curve25519engine", None), size=0x20000, cached=False))
|
||||
self.bus.add_master(name="curve25519engineLS", master=self.curve25519engine.busls)
|
||||
#self.submodules.curve25519_on_sync = BusSynchronizer(width = 1, idomain = "clk100", odomain = "sys")
|
||||
#self.comb += self.curve25519_on_sync.i.eq(self.curve25519engine.power.fields.on)
|
||||
#self.comb += self.crg.curve25519_on.eq(self.curve25519_on_sync.o)
|
||||
self.comb += self.crg.curve25519_on.eq(self.curve25519engine.power.fields.on)
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="SbusFPGA")
|
||||
parser.add_argument("--build", action="store_true", help="Build bitstream")
|
||||
parser.add_argument("--version", default="V1.0", help="SBusFPGA board version (default V1.0)")
|
||||
parser.add_argument("--usb", action="store_true", help="add a USB OHCI controller")
|
||||
builder_args(parser)
|
||||
vivado_build_args(parser)
|
||||
args = parser.parse_args()
|
||||
|
||||
soc = SBusFPGA(**soc_core_argdict(args),
|
||||
version=args.version,
|
||||
usb=args.usb)
|
||||
#soc.add_uart(name="uart", baudrate=115200, fifo_depth=16)
|
||||
|
||||
builder = Builder(soc, **builder_argdict(args))
|
||||
builder.build(**vivado_build_argdict(args), run=args.build)
|
||||
|
||||
# Generate modified CSR registers definitions/access functions to netbsd_csr.h.
|
||||
# should be split per-device (and without base) to still work if we have identical devices in different configurations on multiple boards
|
||||
csr_contents = sbus_to_fpga_export.get_csr_header(
|
||||
regions = soc.csr_regions,
|
||||
constants = soc.constants,
|
||||
csr_base = soc.mem_regions['csr'].origin)
|
||||
write_to_file(os.path.join("netbsd_csr.h"), csr_contents)
|
||||
|
||||
# tells the prom where to find what
|
||||
# just one, as that is board-specific
|
||||
# BEWARE! then need to run 'forth_to_migen_rom.sh' *and* regenerate the bitstream with the proper PROM built-in!
|
||||
# (there's surely a better way...)
|
||||
csr_forth_contents = sbus_to_fpga_export.get_csr_forth_header(
|
||||
csr_regions = soc.csr_regions,
|
||||
mem_regions = soc.mem_regions,
|
||||
constants = soc.constants,
|
||||
csr_base = soc.mem_regions['csr'].origin)
|
||||
write_to_file(os.path.join("prom_csr.fth"), csr_forth_contents)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
94
sbus-to-ztex-gateware-migen/sbus_to_fpga_trng.py
Normal file
94
sbus-to-ztex-gateware-migen/sbus_to_fpga_trng.py
Normal file
@ -0,0 +1,94 @@
|
||||
from migen import *
|
||||
from migen.genlib.fifo import *
|
||||
from litex.soc.interconnect.csr import *
|
||||
|
||||
class NeoRV32TrngWrapper(Module, AutoCSR):
|
||||
def __init__(self, platform):
|
||||
self.add_sources(platform)
|
||||
|
||||
rden_i = Signal()
|
||||
wren_i = Signal()
|
||||
data_i = Signal(32)
|
||||
data_o = Signal(32)
|
||||
|
||||
self.ctrl = CSRStorage(32, description = "CTRL register; bit 0 : disable ; bit 1 : enable")
|
||||
self.data = CSRStatus(32, description = "Rnd Data or 0")
|
||||
|
||||
self.submodules.ctrl_fsm = ctrl_fsm = FSM(reset_state = "Reset")
|
||||
ctrl_fsm.act("Reset",
|
||||
NextState("Idle")
|
||||
)
|
||||
ctrl_fsm.act("Idle",
|
||||
If(self.ctrl.re, # someone has written control
|
||||
If(self.ctrl.storage[0],
|
||||
data_i.eq(0),
|
||||
wren_i.eq(1),
|
||||
).Elif(self.ctrl.storage[1],
|
||||
data_i.eq(0xffffffff),
|
||||
wren_i.eq(1),
|
||||
)
|
||||
),
|
||||
If(self.data.we, # someone has read the data, reset so that the same value is never read twice
|
||||
NextValue(self.data.status, 0),
|
||||
)
|
||||
)
|
||||
|
||||
# fill out an intermediate buffer, one byte every 11 cycles
|
||||
# then copy the 4 bytes to data CST and do it all over again
|
||||
buf = Array(Signal(8) for a in range(4))
|
||||
idx = Signal(2)
|
||||
cnt = Signal(4)
|
||||
self.submodules.upd_fsm = upd_fsm = FSM(reset_state = "Reset")
|
||||
upd_fsm.act("Reset",
|
||||
NextValue(cnt, 11),
|
||||
NextValue(idx, 0),
|
||||
NextState("ByteWait")
|
||||
)
|
||||
upd_fsm.act("ByteWait",
|
||||
If(cnt == 0,
|
||||
rden_i.eq(1),
|
||||
NextState("ByteWrite"),
|
||||
).Else(
|
||||
NextValue(cnt, cnt - 1)
|
||||
)
|
||||
)
|
||||
upd_fsm.act("ByteWrite",
|
||||
If (data_o[31] & data_o[30],
|
||||
NextValue(buf[idx], data_o[0:8]),
|
||||
NextValue(cnt, 11),
|
||||
NextValue(idx, idx + 1),
|
||||
If(idx == 3,
|
||||
NextState("Copy"),
|
||||
).Else(
|
||||
NextState("ByteWait"),
|
||||
)
|
||||
).Else( # try again
|
||||
NextValue(cnt, 11),
|
||||
NextState("ByteWait"),
|
||||
)
|
||||
)
|
||||
upd_fsm.act("Copy",
|
||||
NextValue(self.data.status, Cat(buf[0], buf[1], buf[2], buf[3])),
|
||||
NextValue(buf[0], 0),
|
||||
NextValue(buf[1], 0),
|
||||
NextValue(buf[2], 0),
|
||||
NextValue(buf[3], 0),
|
||||
NextState("ByteWait")
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
self.specials += Instance(self.get_netlist_name(),
|
||||
i_clk_i = ClockSignal("sys"),
|
||||
i_rden_i = rden_i,
|
||||
i_wren_i = wren_i,
|
||||
i_data_i = data_i,
|
||||
o_data_o = data_o)
|
||||
|
||||
def get_netlist_name(self):
|
||||
return "neorv32_trng"
|
||||
|
||||
def add_sources(self, platform):
|
||||
platform.add_source("neorv32_trng_patched.vhd", "vhdl")
|
||||
|
||||
55
sbus-to-ztex-gateware-migen/sbusfpga_stat_ctl.c
Normal file
55
sbus-to-ztex-gateware-migen/sbusfpga_stat_ctl.c
Normal file
@ -0,0 +1,55 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/ioccom.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define SBUSFPGA_STAT_ON _IO(0, 1)
|
||||
#define SBUSFPGA_STAT_OFF _IO(0, 0)
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
const char const * device = "/dev/sbusfpga_stat0";
|
||||
int devfd;
|
||||
int onoff;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s on|off\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strncmp("on", argv[1], 2) == 0) {
|
||||
onoff = 1;
|
||||
} else if (strncmp("off", argv[1], 3) == 0) {
|
||||
onoff = 0;
|
||||
} else {
|
||||
fprintf(stderr, "Usage: %s on|off\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( (devfd = open(device, O_RDWR)) == -1) {
|
||||
perror("can't open device file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (onoff) {
|
||||
case 0:
|
||||
if (ioctl(devfd, SBUSFPGA_STAT_OFF, NULL)) {
|
||||
perror("Turning statistics off failed.");
|
||||
close(devfd);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (ioctl(devfd, SBUSFPGA_STAT_ON, NULL)) {
|
||||
perror("Turning statistics on failed.");
|
||||
close(devfd);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
228
sbus-to-ztex-gateware-migen/sdram_csr.fth
Normal file
228
sbus-to-ztex-gateware-migen/sdram_csr.fth
Normal file
@ -0,0 +1,228 @@
|
||||
: dphy_rst_rd ( -- csr_value )
|
||||
mregs-virt h# 1000 + l@
|
||||
;
|
||||
: dphy_half_sys8x_taps_rd ( -- csr_value )
|
||||
mregs-virt h# 1004 + l@
|
||||
;
|
||||
: dphy_wlevel_en_rd ( -- csr_value )
|
||||
mregs-virt h# 1008 + l@
|
||||
;
|
||||
: dphy_wlevel_strobe_rd ( -- csr_value )
|
||||
mregs-virt h# 100c + l@
|
||||
;
|
||||
: dphy_dly_sel_rd ( -- csr_value )
|
||||
mregs-virt h# 1010 + l@
|
||||
;
|
||||
: dphy_rdly_dq_rst_rd ( -- csr_value )
|
||||
mregs-virt h# 1014 + l@
|
||||
;
|
||||
: dphy_rdly_dq_inc_rd ( -- csr_value )
|
||||
mregs-virt h# 1018 + l@
|
||||
;
|
||||
: dphy_rdly_dq_bitslip_rst_rd ( -- csr_value )
|
||||
mregs-virt h# 101c + l@
|
||||
;
|
||||
: dphy_rdly_dq_bitslip_rd ( -- csr_value )
|
||||
mregs-virt h# 1020 + l@
|
||||
;
|
||||
: dphy_wdly_dq_bitslip_rst_rd ( -- csr_value )
|
||||
mregs-virt h# 1024 + l@
|
||||
;
|
||||
: dphy_wdly_dq_bitslip_rd ( -- csr_value )
|
||||
mregs-virt h# 1028 + l@
|
||||
;
|
||||
: dphy_rdphase_rd ( -- csr_value )
|
||||
mregs-virt h# 102c + l@
|
||||
;
|
||||
: dphy_wrphase_rd ( -- csr_value )
|
||||
mregs-virt h# 1030 + l@
|
||||
;
|
||||
: sdr_dfii_control_rd ( -- csr_value )
|
||||
mregs-virt h# 2000 + l@
|
||||
;
|
||||
: sdr_dfii_pi0_command_rd ( -- csr_value )
|
||||
mregs-virt h# 2004 + l@
|
||||
;
|
||||
: sdr_dfii_pi0_command_issue_rd ( -- csr_value )
|
||||
mregs-virt h# 2008 + l@
|
||||
;
|
||||
: sdr_dfii_pi0_address_rd ( -- csr_value )
|
||||
mregs-virt h# 200c + l@
|
||||
;
|
||||
: sdr_dfii_pi0_baddress_rd ( -- csr_value )
|
||||
mregs-virt h# 2010 + l@
|
||||
;
|
||||
: sdr_dfii_pi0_wrdata_rd ( -- csr_value )
|
||||
mregs-virt h# 2014 + l@
|
||||
;
|
||||
: sdr_dfii_pi0_rddata_rd ( -- csr_value )
|
||||
mregs-virt h# 2018 + l@
|
||||
;
|
||||
: sdr_dfii_pi1_command_rd ( -- csr_value )
|
||||
mregs-virt h# 201c + l@
|
||||
;
|
||||
: sdr_dfii_pi1_command_issue_rd ( -- csr_value )
|
||||
mregs-virt h# 2020 + l@
|
||||
;
|
||||
: sdr_dfii_pi1_address_rd ( -- csr_value )
|
||||
mregs-virt h# 2024 + l@
|
||||
;
|
||||
: sdr_dfii_pi1_baddress_rd ( -- csr_value )
|
||||
mregs-virt h# 2028 + l@
|
||||
;
|
||||
: sdr_dfii_pi1_wrdata_rd ( -- csr_value )
|
||||
mregs-virt h# 202c + l@
|
||||
;
|
||||
: sdr_dfii_pi1_rddata_rd ( -- csr_value )
|
||||
mregs-virt h# 2030 + l@
|
||||
;
|
||||
: sdr_dfii_pi2_command_rd ( -- csr_value )
|
||||
mregs-virt h# 2034 + l@
|
||||
;
|
||||
: sdr_dfii_pi2_command_issue_rd ( -- csr_value )
|
||||
mregs-virt h# 2038 + l@
|
||||
;
|
||||
: sdr_dfii_pi2_address_rd ( -- csr_value )
|
||||
mregs-virt h# 203c + l@
|
||||
;
|
||||
: sdr_dfii_pi2_baddress_rd ( -- csr_value )
|
||||
mregs-virt h# 2040 + l@
|
||||
;
|
||||
: sdr_dfii_pi2_wrdata_rd ( -- csr_value )
|
||||
mregs-virt h# 2044 + l@
|
||||
;
|
||||
: sdr_dfii_pi2_rddata_rd ( -- csr_value )
|
||||
mregs-virt h# 2048 + l@
|
||||
;
|
||||
: sdr_dfii_pi3_command_rd ( -- csr_value )
|
||||
mregs-virt h# 204c + l@
|
||||
;
|
||||
: sdr_dfii_pi3_command_issue_rd ( -- csr_value )
|
||||
mregs-virt h# 2050 + l@
|
||||
;
|
||||
: sdr_dfii_pi3_address_rd ( -- csr_value )
|
||||
mregs-virt h# 2054 + l@
|
||||
;
|
||||
: sdr_dfii_pi3_baddress_rd ( -- csr_value )
|
||||
mregs-virt h# 2058 + l@
|
||||
;
|
||||
: sdr_dfii_pi3_wrdata_rd ( -- csr_value )
|
||||
mregs-virt h# 205c + l@
|
||||
;
|
||||
: sdr_dfii_pi3_rddata_rd ( -- csr_value )
|
||||
mregs-virt h# 2060 + l@
|
||||
;
|
||||
: dphy_rst_wr ( value -- )
|
||||
mregs-virt h# 1000 + l!
|
||||
;
|
||||
: dphy_half_sys8x_taps_wr ( value -- )
|
||||
mregs-virt h# 1004 + l!
|
||||
;
|
||||
: dphy_wlevel_en_wr ( value -- )
|
||||
mregs-virt h# 1008 + l!
|
||||
;
|
||||
: dphy_wlevel_strobe_wr ( value -- )
|
||||
mregs-virt h# 100c + l!
|
||||
;
|
||||
: dphy_dly_sel_wr ( value -- )
|
||||
mregs-virt h# 1010 + l!
|
||||
;
|
||||
: dphy_rdly_dq_rst_wr ( value -- )
|
||||
mregs-virt h# 1014 + l!
|
||||
;
|
||||
: dphy_rdly_dq_inc_wr ( value -- )
|
||||
mregs-virt h# 1018 + l!
|
||||
;
|
||||
: dphy_rdly_dq_bitslip_rst_wr ( value -- )
|
||||
mregs-virt h# 101c + l!
|
||||
;
|
||||
: dphy_rdly_dq_bitslip_wr ( value -- )
|
||||
mregs-virt h# 1020 + l!
|
||||
;
|
||||
: dphy_wdly_dq_bitslip_rst_wr ( value -- )
|
||||
mregs-virt h# 1024 + l!
|
||||
;
|
||||
: dphy_wdly_dq_bitslip_wr ( value -- )
|
||||
mregs-virt h# 1028 + l!
|
||||
;
|
||||
: dphy_rdphase_wr ( value -- )
|
||||
mregs-virt h# 102c + l!
|
||||
;
|
||||
: dphy_wrphase_wr ( value -- )
|
||||
mregs-virt h# 1030 + l!
|
||||
;
|
||||
: sdr_dfii_control_wr ( value -- )
|
||||
mregs-virt h# 2000 + l!
|
||||
;
|
||||
: sdr_dfii_pi0_command_wr ( value -- )
|
||||
mregs-virt h# 2004 + l!
|
||||
;
|
||||
: sdr_dfii_pi0_command_issue_wr ( value -- )
|
||||
mregs-virt h# 2008 + l!
|
||||
;
|
||||
: sdr_dfii_pi0_address_wr ( value -- )
|
||||
mregs-virt h# 200c + l!
|
||||
;
|
||||
: sdr_dfii_pi0_baddress_wr ( value -- )
|
||||
mregs-virt h# 2010 + l!
|
||||
;
|
||||
: sdr_dfii_pi0_wrdata_wr ( value -- )
|
||||
mregs-virt h# 2014 + l!
|
||||
;
|
||||
: sdr_dfii_pi0_rddata_wr ( value -- )
|
||||
mregs-virt h# 2018 + l!
|
||||
;
|
||||
: sdr_dfii_pi1_command_wr ( value -- )
|
||||
mregs-virt h# 201c + l!
|
||||
;
|
||||
: sdr_dfii_pi1_command_issue_wr ( value -- )
|
||||
mregs-virt h# 2020 + l!
|
||||
;
|
||||
: sdr_dfii_pi1_address_wr ( value -- )
|
||||
mregs-virt h# 2024 + l!
|
||||
;
|
||||
: sdr_dfii_pi1_baddress_wr ( value -- )
|
||||
mregs-virt h# 2028 + l!
|
||||
;
|
||||
: sdr_dfii_pi1_wrdata_wr ( value -- )
|
||||
mregs-virt h# 202c + l!
|
||||
;
|
||||
: sdr_dfii_pi1_rddata_wr ( value -- )
|
||||
mregs-virt h# 2030 + l!
|
||||
;
|
||||
: sdr_dfii_pi2_command_wr ( value -- )
|
||||
mregs-virt h# 2034 + l!
|
||||
;
|
||||
: sdr_dfii_pi2_command_issue_wr ( value -- )
|
||||
mregs-virt h# 2038 + l!
|
||||
;
|
||||
: sdr_dfii_pi2_address_wr ( value -- )
|
||||
mregs-virt h# 203c + l!
|
||||
;
|
||||
: sdr_dfii_pi2_baddress_wr ( value -- )
|
||||
mregs-virt h# 2040 + l!
|
||||
;
|
||||
: sdr_dfii_pi2_wrdata_wr ( value -- )
|
||||
mregs-virt h# 2044 + l!
|
||||
;
|
||||
: sdr_dfii_pi2_rddata_wr ( value -- )
|
||||
mregs-virt h# 2048 + l!
|
||||
;
|
||||
: sdr_dfii_pi3_command_wr ( value -- )
|
||||
mregs-virt h# 204c + l!
|
||||
;
|
||||
: sdr_dfii_pi3_command_issue_wr ( value -- )
|
||||
mregs-virt h# 2050 + l!
|
||||
;
|
||||
: sdr_dfii_pi3_address_wr ( value -- )
|
||||
mregs-virt h# 2054 + l!
|
||||
;
|
||||
: sdr_dfii_pi3_baddress_wr ( value -- )
|
||||
mregs-virt h# 2058 + l!
|
||||
;
|
||||
: sdr_dfii_pi3_wrdata_wr ( value -- )
|
||||
mregs-virt h# 205c + l!
|
||||
;
|
||||
: sdr_dfii_pi3_rddata_wr ( value -- )
|
||||
mregs-virt h# 2060 + l!
|
||||
;
|
||||
533
sbus-to-ztex-gateware-migen/sdram_init.fth
Normal file
533
sbus-to-ztex-gateware-migen/sdram_init.fth
Normal file
@ -0,0 +1,533 @@
|
||||
headers
|
||||
|
||||
fload sdram_csr.fth
|
||||
|
||||
external
|
||||
|
||||
: popcnt ( n -- u)
|
||||
0 swap
|
||||
BEGIN dup WHILE tuck 1 AND + swap 1 rshift REPEAT
|
||||
DROP
|
||||
;
|
||||
|
||||
: cdelay ( count -- )
|
||||
\ Forth loop always have a least one iteration
|
||||
dup 0<> if
|
||||
0 do noop loop
|
||||
else drop then
|
||||
;
|
||||
|
||||
headers
|
||||
|
||||
: sdram_software_control_on ( -- )
|
||||
sdr_dfii_control_rd
|
||||
h# e <> if h# e sdr_dfii_control_wr then
|
||||
;
|
||||
|
||||
: sdram_software_control_off ( -- )
|
||||
sdr_dfii_control_rd
|
||||
h# 1 <> if h# 1 sdr_dfii_control_wr then
|
||||
;
|
||||
|
||||
: command_p0 ( cmd -- )
|
||||
sdr_dfii_pi0_command_wr
|
||||
1 sdr_dfii_pi0_command_issue_wr
|
||||
;
|
||||
: command_p1 ( cmd -- )
|
||||
sdr_dfii_pi1_command_wr
|
||||
1 sdr_dfii_pi1_command_issue_wr
|
||||
;
|
||||
: command_p2 ( cmd -- )
|
||||
sdr_dfii_pi2_command_wr
|
||||
1 sdr_dfii_pi2_command_issue_wr
|
||||
;
|
||||
: command_p3 ( cmd -- )
|
||||
sdr_dfii_pi3_command_wr
|
||||
1 sdr_dfii_pi3_command_issue_wr
|
||||
;
|
||||
|
||||
: init_sequence ( -- )
|
||||
.( init_sequence ) cr
|
||||
h# 0 sdr_dfii_pi0_address_wr
|
||||
h# 0 sdr_dfii_pi0_baddress_wr
|
||||
h# c sdr_dfii_control_wr
|
||||
50 ms
|
||||
|
||||
h# 0 sdr_dfii_pi0_address_wr
|
||||
h# 0 sdr_dfii_pi0_baddress_wr
|
||||
h# e sdr_dfii_control_wr
|
||||
10 ms
|
||||
|
||||
h# 200 sdr_dfii_pi0_address_wr
|
||||
h# 2 sdr_dfii_pi0_baddress_wr
|
||||
h# f command_p0
|
||||
|
||||
h# 0 sdr_dfii_pi0_address_wr
|
||||
h# 3 sdr_dfii_pi0_baddress_wr
|
||||
h# f command_p0
|
||||
|
||||
h# 6 sdr_dfii_pi0_address_wr
|
||||
h# 1 sdr_dfii_pi0_baddress_wr
|
||||
h# f command_p0
|
||||
|
||||
h# 920 sdr_dfii_pi0_address_wr
|
||||
h# 0 sdr_dfii_pi0_baddress_wr
|
||||
h# f command_p0
|
||||
200 cdelay
|
||||
|
||||
h# 400 sdr_dfii_pi0_address_wr
|
||||
0 sdr_dfii_pi0_baddress_wr
|
||||
h# 3 command_p0
|
||||
200 cdelay
|
||||
;
|
||||
|
||||
: sdram_read_leveling_rst_delay ( modulenum -- )
|
||||
h# 1 swap << dphy_dly_sel_wr
|
||||
h# 1 dphy_rdly_dq_rst_wr
|
||||
h# 0 dphy_dly_sel_wr
|
||||
;
|
||||
|
||||
: sdram_read_leveling_inc_delay ( modulenum -- )
|
||||
h# 1 swap << dphy_dly_sel_wr
|
||||
h# 1 dphy_rdly_dq_inc_wr
|
||||
h# 0 dphy_dly_sel_wr
|
||||
;
|
||||
|
||||
: sdram_read_leveling_rst_bitslip ( modulenum -- )
|
||||
h# 1 swap << dphy_dly_sel_wr
|
||||
h# 1 dphy_rdly_dq_bitslip_rst_wr
|
||||
h# 0 dphy_dly_sel_wr
|
||||
;
|
||||
|
||||
: sdram_read_leveling_inc_bitslip ( modulenum -- )
|
||||
h# 1 swap << dphy_dly_sel_wr
|
||||
h# 1 dphy_rdly_dq_bitslip_wr
|
||||
h# 0 dphy_dly_sel_wr
|
||||
;
|
||||
|
||||
: lfsr ( bits prev -- res )
|
||||
dup 1 and not ( bits prev -- bits prev ~{prev&1} )
|
||||
swap 1 >> ( bits prev ~{prev&1} -- bits ~{prev&1} {prev>>1} )
|
||||
swap ( bits prev ~{prev&1} -- bits {prev>>1} ~{prev&1} )
|
||||
rot ( bits {prev>>1} ~{prev&1} -- {prev>>1} ~{prev&1} bits )
|
||||
\ assume bits is 32, 'cause it is
|
||||
drop h# 80200003 ( {prev>>1} ~{prev&1} bits -- {prev>>1} ~{prev&1} lfsr_taps[bits] )
|
||||
and
|
||||
xor
|
||||
;
|
||||
|
||||
: sdram_activate_test_row ( -- )
|
||||
h# 0 sdr_dfii_pi0_address_wr
|
||||
h# 0 sdr_dfii_pi0_baddress_wr
|
||||
h# 9 command_p0
|
||||
15 cdelay
|
||||
;
|
||||
|
||||
: sdram_precharge_test_row ( -- )
|
||||
h# 0 sdr_dfii_pi0_address_wr
|
||||
h# 0 sdr_dfii_pi0_baddress_wr
|
||||
h# b command_p0
|
||||
15 cdelay
|
||||
;
|
||||
|
||||
: command_px ( phase value -- )
|
||||
over 3 = if dup command_p3 then
|
||||
over 2 = if dup command_p2 then
|
||||
over 1 = if dup command_p1 then
|
||||
over 0 = if dup command_p0 then
|
||||
2drop
|
||||
;
|
||||
|
||||
: command_prd ( value -- )
|
||||
dphy_rdphase_rd
|
||||
swap command_px
|
||||
;
|
||||
|
||||
: command_pwr ( value -- )
|
||||
dphy_wrphase_rd
|
||||
swap command_px
|
||||
;
|
||||
|
||||
: sdr_dfii_pix_address_wr ( phase value -- )
|
||||
over 3 = if dup sdr_dfii_pi3_address_wr then
|
||||
over 2 = if dup sdr_dfii_pi2_address_wr then
|
||||
over 1 = if dup sdr_dfii_pi1_address_wr then
|
||||
over 0 = if dup sdr_dfii_pi0_address_wr then
|
||||
2drop
|
||||
;
|
||||
|
||||
: sdr_dfii_pird_address_wr ( value -- )
|
||||
dphy_rdphase_rd
|
||||
swap sdr_dfii_pix_address_wr
|
||||
;
|
||||
|
||||
: sdr_dfii_piwr_address_wr ( value -- )
|
||||
dphy_wrphase_rd
|
||||
swap sdr_dfii_pix_address_wr
|
||||
;
|
||||
|
||||
: sdr_dfii_pix_baddress_wr ( phase value -- )
|
||||
over 3 = if dup sdr_dfii_pi3_baddress_wr then
|
||||
over 2 = if dup sdr_dfii_pi2_baddress_wr then
|
||||
over 1 = if dup sdr_dfii_pi1_baddress_wr then
|
||||
over 0 = if dup sdr_dfii_pi0_baddress_wr then
|
||||
2drop
|
||||
;
|
||||
|
||||
: sdr_dfii_pird_baddress_wr ( value -- )
|
||||
dphy_rdphase_rd
|
||||
swap sdr_dfii_pix_baddress_wr
|
||||
;
|
||||
|
||||
: sdr_dfii_piwr_baddress_wr ( value -- )
|
||||
dphy_wrphase_rd
|
||||
swap sdr_dfii_pix_baddress_wr
|
||||
;
|
||||
|
||||
: sdr_wr_rd_chk_tst_pat_get ( seed -- A B C D )
|
||||
\ .( sdr_wr_rd_chk_tst_pat_get ) cr
|
||||
dup 42 = if h# 00000080 swap then
|
||||
dup 42 = if h# 00000000 swap then
|
||||
dup 42 = if h# 00000000 swap then
|
||||
dup 42 = if h# 15090700 swap then
|
||||
dup 84 = if h# 00000000 swap then
|
||||
dup 84 = if h# 00000000 swap then
|
||||
dup 84 = if h# 00000000 swap then
|
||||
dup 84 = if h# 2a150907 swap then
|
||||
drop
|
||||
;
|
||||
|
||||
: sdr_wr_rd_check_test_pattern ( modulenum seed -- errors )
|
||||
\ .( sdr_wr_rd_check_test_pattern ) cr
|
||||
sdram_activate_test_row
|
||||
dup sdr_wr_rd_chk_tst_pat_get
|
||||
\ should have the 4 patterns on top of the stack: modulenum seed p0 p1 p2 p3
|
||||
sdr_dfii_pi0_wrdata_wr
|
||||
sdr_dfii_pi1_wrdata_wr
|
||||
sdr_dfii_pi2_wrdata_wr
|
||||
sdr_dfii_pi3_wrdata_wr
|
||||
\ should be back at modulenum seed
|
||||
h# 0 sdr_dfii_piwr_address_wr
|
||||
h# 0 sdr_dfii_piwr_baddress_wr
|
||||
h# 17 command_pwr
|
||||
15 cdelay
|
||||
|
||||
h# 0 sdr_dfii_pird_address_wr
|
||||
h# 0 sdr_dfii_pird_baddress_wr
|
||||
h# 25 command_prd
|
||||
15 cdelay
|
||||
|
||||
sdram_precharge_test_row
|
||||
|
||||
sdr_wr_rd_chk_tst_pat_get
|
||||
\ should have the 4 patterns on top of the stack: modulenum p0 p1 p2 p3
|
||||
sdr_dfii_pi0_rddata_rd xor popcnt
|
||||
\ should be at modulenum p0 p1 p2 errors
|
||||
swap sdr_dfii_pi0_rddata_rd xor popcnt +
|
||||
\ should be at modulenum p0 p1 errors
|
||||
swap sdr_dfii_pi0_rddata_rd xor popcnt +
|
||||
\ should be at modulenum p0 errors
|
||||
swap sdr_dfii_pi0_rddata_rd xor popcnt +
|
||||
\ should be at modulenum errors
|
||||
\ drop modulenum
|
||||
nip
|
||||
;
|
||||
|
||||
: sdram_read_leveling_scan_module ( modulenum bitslip -- score )
|
||||
\ .( sdram_read_leveling_scan_module ) cr
|
||||
over sdram_read_leveling_rst_delay
|
||||
\ push score
|
||||
0
|
||||
\ we should be at 'modulenum bitslip score'
|
||||
32 0 do
|
||||
\ .( starting rd_lvl_scan loop with stack: ) .s cr
|
||||
2 pick 42 sdr_wr_rd_check_test_pattern
|
||||
\ now we have an error count at the top
|
||||
3 pick 84 sdr_wr_rd_check_test_pattern
|
||||
\ merge both error count
|
||||
+
|
||||
\ we should be at 'modulenum bitslip score errorcount'
|
||||
dup 0=
|
||||
\ we should be at 'modulenum bitslip score errorcount working?'
|
||||
if 16384 else 0 then
|
||||
\ we should be at 'modulenum bitslip score errorcount (0|16384)'
|
||||
swap 512 swap -
|
||||
\ we should be at 'modulenum bitslip score (0|16384) (512-errorcount)'
|
||||
+
|
||||
+
|
||||
\ we should be at 'modulenum bitslip score'
|
||||
2 pick sdram_read_leveling_inc_delay
|
||||
loop
|
||||
nip
|
||||
nip
|
||||
;
|
||||
|
||||
: sdr_wr_lat_cal_bitslip_loop ( modulenum bestbitslip bestscore bitslip -- modulenum bestbitslip bestscore )
|
||||
\ .( sdr_wr_lat_cal_bitslip_loop for module: ) 3 pick . .( bitslip: ) dup . cr
|
||||
\ .( sdr_wr_lat_cal_bitslip_loop, stack: ) .s cr
|
||||
1 4 pick << dphy_dly_sel_wr ( '4 pick' will extract modulenum, needed as we're stacking the '1' )
|
||||
1 dphy_wdly_dq_bitslip_rst_wr
|
||||
\ Forth loop always have a least one iteration
|
||||
dup 0<> if
|
||||
dup 0 do
|
||||
1 dphy_wdly_dq_bitslip_wr
|
||||
loop
|
||||
then
|
||||
0 dphy_dly_sel_wr
|
||||
\ .( sdr_wr_lat_cal_bitslip_loop after bitslip init loop, stack: ) .s cr
|
||||
\ push current score
|
||||
0 ( we should be at 'modulenum bestbitslip bestscore bitslip score' )
|
||||
4 pick sdram_read_leveling_rst_bitslip
|
||||
8 0 do
|
||||
4 pick over sdram_read_leveling_scan_module
|
||||
\ we should be at 'modulenum bestbitslip bestscore bitslip score score', max will merge scores
|
||||
max
|
||||
\ we should be at 'modulenum bestbitslip bestscore bitslip score' again
|
||||
4 pick sdram_read_leveling_inc_bitslip
|
||||
loop
|
||||
.( sdr_wr_lat_cal_bitslip_loop after bitslip check loop, stack: ) .s cr
|
||||
dup 3 pick >
|
||||
if
|
||||
\ .( lat_cal best bitslip was: ) 3 pick . .( with score: ) 2 pick . cr
|
||||
2swap
|
||||
.( lat_cal best bitslip now: ) 3 pick . .( with score: ) 2 pick . cr
|
||||
then
|
||||
2drop
|
||||
\ .( sdr_wr_lat_cal_bitslip_loop end, stack: ) .s cr
|
||||
;
|
||||
|
||||
: sdr_wr_lat_cal_module_loop ( modulenum -- )
|
||||
.( sdr_wr_lat_cal_module_loop for module: ) dup . cr
|
||||
\ push best_bitslip
|
||||
-1
|
||||
\ push best_score
|
||||
0
|
||||
\ we should have 'modulenum 1 0'
|
||||
8 0 do
|
||||
i sdr_wr_lat_cal_bitslip_loop
|
||||
2 +loop
|
||||
\ we should be at 'modulenum bestbitslip bestscore'
|
||||
\ we don't need score anymore
|
||||
drop
|
||||
\ we should be at 'modulenum bestbitslip'
|
||||
1 2 pick << dphy_dly_sel_wr
|
||||
1 dphy_wdly_dq_bitslip_rst_wr
|
||||
.( sdr_wr_lat_cal_module_loop: best bitslip: ) dup . cr
|
||||
\ loop that consumes bestbitslip as the upper bound
|
||||
\ Forth loop always have a least one iteration
|
||||
dup 0<> if
|
||||
0 do
|
||||
1 dphy_wdly_dq_bitslip_wr
|
||||
loop
|
||||
else drop then
|
||||
0 dphy_dly_sel_wr
|
||||
\ drop the modulenum
|
||||
drop
|
||||
;
|
||||
|
||||
: sdram_write_latency_calibration ( -- )
|
||||
.( sdram_write_latency_calibration ) cr
|
||||
2 0 do
|
||||
i sdr_wr_lat_cal_module_loop
|
||||
loop
|
||||
;
|
||||
|
||||
: sdram_leveling_center_module ( modulenum -- )
|
||||
.( sdram_leveling_center_module ) cr
|
||||
dup sdram_read_leveling_rst_delay
|
||||
\ push delay_min
|
||||
-1
|
||||
\ push delay
|
||||
0
|
||||
\ we should be at 'modulenum delay_min delay'
|
||||
begin
|
||||
\ .( starting lvl_center loop with stack: ) .s cr
|
||||
2 pick 42 sdr_wr_rd_check_test_pattern
|
||||
.( we should be at 'modulenum delay_min delay error' stack: ) .s cr
|
||||
3 pick 84 sdr_wr_rd_check_test_pattern
|
||||
.( we should be at 'modulenum delay_min delay error error' stack: ) .s cr
|
||||
+
|
||||
\ we should be at 'modulenum delay_min delay error'
|
||||
\ .( we should be at 'modulenum delay_min delay error' stack: ) .s cr
|
||||
0=
|
||||
\ we should be at 'modulenum delay_min delay working'
|
||||
\ .( we should be at 'modulenum delay_min delay working' stack: ) .s cr
|
||||
2 pick 0< and
|
||||
\ we should be at 'modulenum delay_min delay {working&delay_min<0}'
|
||||
\ .( we should be at 'modulenum delay_min delay {working&delay_min<0}' stack: ) .s cr
|
||||
dup if rot drop 2dup rot drop then
|
||||
not
|
||||
\ we should be at 'modulenum new_delay_min delay !{working&delay_min<0}'
|
||||
\ .( we should be at 'modulenum new_delay_min delay !{working&delay_min<0}' stack: ) .s cr
|
||||
\ test delay before incrementing, if already 31 no point in continuing/incrementing
|
||||
over 31 <
|
||||
\ .( we should be at 'modulenum new_delay_min delay !{working&delay_min<0} <31' stack: ) .s cr
|
||||
dup if rot 1+ -rot then
|
||||
dup if 4 pick sdram_read_leveling_inc_delay then
|
||||
\ and the conditions to signal end-of-loop
|
||||
and
|
||||
\ .( we should be at 'modulenum new_delay_min delay !{working&delay_min<0}&<31' stack: ) .s cr
|
||||
\ .( finishing lvl_center loop with stack: ) .s cr
|
||||
not until
|
||||
\ we should be at 'modulenum new_delay_min delay', the while has consumed the condition
|
||||
.( we should be at 'modulenum new_delay_min delay' stack: ) .s cr
|
||||
1+
|
||||
2 pick sdram_read_leveling_inc_delay
|
||||
\ build a clean stack, startin with a copy of modulenum
|
||||
2 pick
|
||||
\ push delay_max
|
||||
-1
|
||||
\ we're at 'modulenum new_delay_min delay modulenum delay_max'
|
||||
\ push delay
|
||||
2 pick
|
||||
\ we're at 'modulenum new_delay_min delay modulenum delay_max delay'
|
||||
.( we should be at 'modulenum new_delay_min delay modulenum delay_max delay ' stack: ) .s cr
|
||||
\ this is almost the same loop, except with !working instead of working and delay_max instead of delay_min
|
||||
begin
|
||||
2 pick 42 sdr_wr_rd_check_test_pattern
|
||||
3 pick 84 sdr_wr_rd_check_test_pattern
|
||||
+
|
||||
\ we should be at 'modulenum delay_max delay error'
|
||||
0<>
|
||||
\ we should be at 'modulenum delay_max delay !working'
|
||||
2 pick 0< and
|
||||
\ we should be at 'modulenum delay_max delay {!working&delay_max<0}'
|
||||
dup if rot drop 2dup rot drop then
|
||||
not
|
||||
\ we should be at 'modulenum new_delay_max delay !{!working&delay_max<0}'
|
||||
\ test delay before incrementing, if already 31 no point in continuing/incrementing
|
||||
over 31 <
|
||||
dup not if rot 1+ -rot then
|
||||
dup not if 4 pick sdram_read_leveling_inc_delay then
|
||||
\ and the conditions to signal end-of-loop
|
||||
and
|
||||
not until
|
||||
\ we should be at 'modulenum new_delay_min delay modulenum new_delay_max delay', the while has consumed the condition
|
||||
.( we should be at 'modulenum new_delay_min delay modulenum new_delay_max delay ' stack: ) .s cr
|
||||
\ keep delay if new_delay_max<0, new_delay_max otherwise
|
||||
over 0< if nip else drop then
|
||||
\ we should be at 'modulenum new_delay_min delay modulenum new_delay_max'
|
||||
nip
|
||||
nip
|
||||
\ we should be at 'modulenum new_delay_min new_delay_max'
|
||||
.( we should be at 'modulenum new_delay_min new_delay_max' stack: ) .s cr
|
||||
\ compute delay_mid
|
||||
2dup + 2/ 32 mod
|
||||
\ we should be at 'modulenum new_delay_min new_delay_max {{new_delay_min+new_delay_max}/2%32}'
|
||||
\ compute delay_range
|
||||
3dup drop swap - 2/
|
||||
\ we should be at 'modulenum new_delay_min new_delay_max {{new_delay_min+new_delay_max}/2%32} {{new_delay_max-new_delay_min}/2}'
|
||||
.( we should be at 'modulenum new_delay_min new_delay_max delay_mid delay_range ' stack: ) .s cr
|
||||
4 pick sdram_read_leveling_rst_delay
|
||||
100 cdelay
|
||||
\ Forth loop always have a least one iteration
|
||||
over 0<> if
|
||||
over 0 do
|
||||
4 pick sdram_read_leveling_inc_delay
|
||||
100 cdelay
|
||||
loop
|
||||
then
|
||||
drop
|
||||
drop
|
||||
drop
|
||||
drop
|
||||
drop
|
||||
;
|
||||
|
||||
: sdr_rd_lvl_bitslip_loop ( modulenum bestbitslip bestscore bitslip -- modulenum bestbitslip bestscore )
|
||||
\ .( sdr_rd_lvl_bitslip_loop, stack: ) .s cr
|
||||
3 pick over sdram_read_leveling_scan_module
|
||||
\ we should be at 'modulenum bestbitslip bestscore bitslip score'
|
||||
4 pick sdram_leveling_center_module
|
||||
\ preserve a bitslip for the later test
|
||||
over
|
||||
\ (we should be at 'modulenum bestbitslip bestscore bitslip score bitslip') move it out of the way
|
||||
.( we should be at 'modulenum bestbitslip bestscore bitslip score bitslip' stack: ) .s cr
|
||||
5 roll ( 'modulenum bestscore bitslip score bitslip bestbitslip' )
|
||||
5 roll ( 'modulenum bitslip score bitslip bestbitslip bestscore' )
|
||||
5 roll ( 'modulenum score bitslip bestbitslip bestscore bitslip' )
|
||||
5 roll ( 'modulenum bitslip bestbitslip bestscore bitslip score' )
|
||||
.( we should be at 'modulenum bitslip bestbitslip bestscore bitslip score' stack: ) .s cr
|
||||
\ compare the score and bestcore
|
||||
dup 3 pick >
|
||||
if
|
||||
2swap
|
||||
.( rd_lvl best bitslip now: ) 3 pick . .( with score: ) 2 pick . cr
|
||||
then
|
||||
2drop
|
||||
\ we should be at 'modulenum bitslip bestbitslip bestscore'
|
||||
rot
|
||||
\ we should be at 'modulenum bestbitslip bestscore bitslip'
|
||||
.( we should be at 'modulenum bestbitslip bestscore bitslip' stack: ) .s cr
|
||||
7 <> if 2 pick sdram_read_leveling_inc_bitslip then
|
||||
;
|
||||
|
||||
: sdr_rd_lvl_module_loop ( modulenum -- )
|
||||
.( sdr_rd_lvl_module_loop ) cr
|
||||
1 over << sdram_read_leveling_rst_bitslip
|
||||
\ push best_bitslip
|
||||
0
|
||||
\ push best_score
|
||||
0
|
||||
\ we should have 'modulenum 0 0'
|
||||
8 0 do
|
||||
i sdr_rd_lvl_bitslip_loop
|
||||
loop
|
||||
\ don't need the score anymore
|
||||
drop
|
||||
2 pick sdram_read_leveling_rst_bitslip
|
||||
.( sdr_rd_lvl_module_loop, best bitslip: ) dup . cr
|
||||
\ Forth loop always have a least one iteration
|
||||
dup 0<> if
|
||||
\ consume best_bitslip as loop upper bound
|
||||
0 do
|
||||
dup sdram_leveling_center_module
|
||||
loop
|
||||
else drop then
|
||||
drop
|
||||
;
|
||||
|
||||
: sdram_read_leveling ( -- )
|
||||
.( sdram_read_leveling ) cr
|
||||
2 0 do
|
||||
i sdr_rd_lvl_module_loop
|
||||
loop
|
||||
;
|
||||
|
||||
: sdram_leveling ( -- )
|
||||
.( sdram_leveling ) cr
|
||||
sdram_software_control_on
|
||||
2 0 do
|
||||
i sdram_read_leveling_rst_delay
|
||||
i sdram_read_leveling_rst_bitslip
|
||||
loop
|
||||
sdram_write_latency_calibration
|
||||
sdram_read_leveling
|
||||
sdram_software_control_off
|
||||
;
|
||||
|
||||
external
|
||||
|
||||
: init_sdram ( -- )
|
||||
.( init_sdram ) cr
|
||||
2 dphy_rdphase_wr
|
||||
3 dphy_wrphase_wr
|
||||
sdram_software_control_on
|
||||
1 dphy_rst_wr
|
||||
1 ms
|
||||
0 dphy_rst_wr
|
||||
1 ms
|
||||
.( going to init_sequence ) cr
|
||||
init_sequence
|
||||
.( going to sdram_leveling ) cr
|
||||
sdram_leveling
|
||||
\ redundant
|
||||
sdram_software_control_off
|
||||
;
|
||||
|
||||
: init! ( -- )
|
||||
.( init ) cr
|
||||
map-in-mregs
|
||||
init_sdram
|
||||
map-out-mregs
|
||||
;
|
||||
237
sbus-to-ztex-gateware-migen/ztex213_sbus.py
Normal file
237
sbus-to-ztex-gateware-migen/ztex213_sbus.py
Normal file
@ -0,0 +1,237 @@
|
||||
#
|
||||
# This file is part of LiteX-Boards.
|
||||
#
|
||||
# Support for the ZTEX USB-FGPA Module 2.13:
|
||||
# <https://www.ztex.de/usb-fpga-2/usb-fpga-2.13.e.html>
|
||||
# With (no-so-optional) expansion, either the ZTEX Debug board:
|
||||
# <https://www.ztex.de/usb-fpga-2/debug.e.html>
|
||||
# Or the SBusFPGA adapter board:
|
||||
# <https://github.com/rdolbeau/SBusFPGA>
|
||||
#
|
||||
# Copyright (c) 2015 Yann Sionneau <yann.sionneau@gmail.com>
|
||||
# Copyright (c) 2015-2019 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||
# Copyright (c) 2020-2021 Romain Dolbeau <romain@dolbeau.org>
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
from litex.build.generic_platform import *
|
||||
from litex.build.xilinx import XilinxPlatform
|
||||
from litex.build.openocd import OpenOCD
|
||||
|
||||
# IOs ----------------------------------------------------------------------------------------------
|
||||
|
||||
# FPGA daughterboard I/O
|
||||
|
||||
_io = [
|
||||
## 48 MHz clock reference
|
||||
("clk48", 0, Pins("P15"), IOStandard("LVCMOS33")),
|
||||
## embedded 256 MiB DDR3 DRAM
|
||||
("ddram", 0,
|
||||
Subsignal("a", Pins("C5 B6 C7 D5 A3 E7 A4 C6", "A6 D8 B2 A5 B3 B7"),
|
||||
IOStandard("SSTL135")),
|
||||
Subsignal("ba", Pins("E5 A1 E6"), IOStandard("SSTL135")),
|
||||
Subsignal("ras_n", Pins("E3"), IOStandard("SSTL135")),
|
||||
Subsignal("cas_n", Pins("D3"), IOStandard("SSTL135")),
|
||||
Subsignal("we_n", Pins("D4"), IOStandard("SSTL135")),
|
||||
# Subsignal("cs_n", Pins(""), IOStandard("SSTL135")),
|
||||
Subsignal("dm", Pins("G1 G6"), IOStandard("SSTL135")),
|
||||
Subsignal("dq", Pins(
|
||||
"H1 F1 E2 E1 F4 C1 F3 D2",
|
||||
"G4 H5 G3 H6 J2 J3 K1 K2"),
|
||||
IOStandard("SSTL135"),
|
||||
Misc("IN_TERM=UNTUNED_SPLIT_40")),
|
||||
Subsignal("dqs_p", Pins("H2 J4"),
|
||||
IOStandard("DIFF_SSTL135"),
|
||||
Misc("IN_TERM=UNTUNED_SPLIT_40")),
|
||||
Subsignal("dqs_n", Pins("G2 H4"),
|
||||
IOStandard("DIFF_SSTL135"),
|
||||
Misc("IN_TERM=UNTUNED_SPLIT_40")),
|
||||
Subsignal("clk_p", Pins("C4"), IOStandard("DIFF_SSTL135")),
|
||||
Subsignal("clk_n", Pins("B4"), IOStandard("DIFF_SSTL135")),
|
||||
Subsignal("cke", Pins("B1"), IOStandard("SSTL135")),
|
||||
Subsignal("odt", Pins("F5"), IOStandard("SSTL135")),
|
||||
Subsignal("reset_n", Pins("J5"), IOStandard("SSTL135")),
|
||||
Misc("SLEW=FAST"),
|
||||
),
|
||||
]
|
||||
|
||||
# SBusFPGA I/O
|
||||
|
||||
_sbus_io_v1_0 = [
|
||||
## leds on the SBus board
|
||||
("user_led", 0, Pins("U8"), IOStandard("lvcmos33")), #LED0
|
||||
("user_led", 1, Pins("U7"), IOStandard("lvcmos33")), #LED1
|
||||
("user_led", 2, Pins("U6"), IOStandard("lvcmos33")), #LED2
|
||||
("user_led", 3, Pins("T8"), IOStandard("lvcmos33")), #LED3
|
||||
("user_led", 4, Pins("P4"), IOStandard("lvcmos33")), #LED4
|
||||
("user_led", 5, Pins("P3"), IOStandard("lvcmos33")), #LED5
|
||||
("user_led", 6, Pins("T1"), IOStandard("lvcmos33")), #LED6
|
||||
("user_led", 7, Pins("R1"), IOStandard("lvcmos33")), #LED7
|
||||
#("user_led", 8, Pins("U1"), IOStandard("lvcmos33")), #SBUS_DATA_OE_LED
|
||||
#("user_led", 9, Pins("T3"), IOStandard("lvcmos33")), #SBUS_DATA_OE_LED_2
|
||||
## serial header for console
|
||||
("serial", 0,
|
||||
Subsignal("tx", Pins("V9")), # FIXME: might be the other way round
|
||||
Subsignal("rx", Pins("U9")),
|
||||
IOStandard("LVCMOS33")
|
||||
),
|
||||
## sdcard connector
|
||||
("spisdcard", 0,
|
||||
Subsignal("clk", Pins("R8")),
|
||||
Subsignal("mosi", Pins("T5"), Misc("PULLUP")),
|
||||
Subsignal("cs_n", Pins("V6"), Misc("PULLUP")),
|
||||
Subsignal("miso", Pins("V5"), Misc("PULLUP")),
|
||||
Misc("SLEW=FAST"),
|
||||
IOStandard("LVCMOS33"),
|
||||
),
|
||||
("sdcard", 0,
|
||||
Subsignal("data", Pins("V5 V4 V7 V6"), Misc("PULLUP")),
|
||||
Subsignal("cmd", Pins("T5"), Misc("PULLUP")),
|
||||
Subsignal("clk", Pins("R8")),
|
||||
#Subsignal("cd", Pins("V6")),
|
||||
Misc("SLEW=FAST"),
|
||||
IOStandard("LVCMOS33"),
|
||||
),
|
||||
]
|
||||
|
||||
_sbus_io_v1_2 = [
|
||||
## leds on the SBus board
|
||||
## serial header for console
|
||||
("serial", 0,
|
||||
Subsignal("tx", Pins("V9")), # FIXME: might be the other way round
|
||||
Subsignal("rx", Pins("U9")),
|
||||
IOStandard("LVCMOS33")
|
||||
),
|
||||
## sdcard connector
|
||||
("spisdcard", 0,
|
||||
Subsignal("clk", Pins("R8")),
|
||||
Subsignal("mosi", Pins("T5"), Misc("PULLUP")),
|
||||
Subsignal("cs_n", Pins("V6"), Misc("PULLUP")),
|
||||
Subsignal("miso", Pins("V5"), Misc("PULLUP")),
|
||||
Misc("SLEW=FAST"),
|
||||
IOStandard("LVCMOS33"),
|
||||
),
|
||||
("sdcard", 0,
|
||||
Subsignal("data", Pins("V5 V4 V7 V6"), Misc("PULLUP")),
|
||||
Subsignal("cmd", Pins("T5"), Misc("PULLUP")),
|
||||
Subsignal("clk", Pins("R8")),
|
||||
#Subsignal("cd", Pins("V6")),
|
||||
Misc("SLEW=FAST"),
|
||||
IOStandard("LVCMOS33"),
|
||||
),
|
||||
## USB
|
||||
("usb", 0,
|
||||
Subsignal("dp", Pins("U8")), # Serial TX
|
||||
Subsignal("dm", Pins("U7")), # Serial RX
|
||||
IOStandard("LVCMOS33"))
|
||||
]
|
||||
|
||||
_sbus_sbus_v1_0 = [
|
||||
("SBUS_3V3_CLK", 0, Pins("D15"), IOStandard("lvttl")),
|
||||
("SBUS_3V3_ASs", 0, Pins("T4"), IOStandard("lvttl")),
|
||||
("SBUS_3V3_BGs", 0, Pins("T6"), IOStandard("lvttl")),
|
||||
("SBUS_3V3_BRs", 0, Pins("R6"), IOStandard("lvttl")),
|
||||
("SBUS_3V3_ERRs", 0, Pins("V2"), IOStandard("lvttl")),
|
||||
("SBUS_DATA_OE_LED", 0, Pins("U1"), IOStandard("lvttl")),
|
||||
("SBUS_DATA_OE_LED_2", 0, Pins("T3"), IOStandard("lvttl")),
|
||||
("SBUS_3V3_RSTs", 0, Pins("U2"), IOStandard("lvttl")),
|
||||
("SBUS_3V3_SELs", 0, Pins("K6"), IOStandard("lvttl")),
|
||||
("SBUS_3V3_INT1s", 0, Pins("R3"), IOStandard("lvttl")),
|
||||
("SBUS_3V3_INT7s", 0, Pins("N5"), IOStandard("lvttl")),
|
||||
("SBUS_3V3_PPRD", 0, Pins("N6"), IOStandard("lvttl")),
|
||||
("SBUS_OE", 0, Pins("P5"), IOStandard("lvttl")),
|
||||
("SBUS_3V3_ACKs", 0, Pins("M6 L6 N4"), IOStandard("lvttl")),
|
||||
("SBUS_3V3_SIZ", 0, Pins("R7 U3 V1"), IOStandard("lvttl")),
|
||||
("SBUS_3V3_D", 0, Pins("J18 K16 J17 K15 K13 J15 J13 J14 H14 H17 G14 G17 G16 G18 H16 F18 F16 E18 F15 D18 E17 G13 D17 F13 F14 E16 E15 C17 C16 A18 B18 C15"), IOStandard("lvttl")),
|
||||
("SBUS_3V3_PA", 0, Pins("B16 B17 D14 C14 D12 A16 A15 B14 B13 B12 C12 A14 A13 B11 A11 M4 R2 M3 P2 M2 N2 K5 N1 L4 M1 L3 L1 K3"), IOStandard("lvttl")),
|
||||
]
|
||||
_sbus_sbus_v1_2 = [
|
||||
("SBUS_3V3_CLK", 0, Pins("D15"), IOStandard("lvttl")),
|
||||
("SBUS_3V3_ASs", 0, Pins("T4"), IOStandard("lvttl")),
|
||||
("SBUS_3V3_BGs", 0, Pins("R7"), IOStandard("lvttl")), # moved
|
||||
("SBUS_3V3_BRs", 0, Pins("R6"), IOStandard("lvttl")),
|
||||
("SBUS_3V3_ERRs", 0, Pins("D13"), IOStandard("lvttl")), # moved
|
||||
("SBUS_DATA_OE_LED", 0, Pins("U1"), IOStandard("lvttl")),
|
||||
#("SBUS_DATA_OE_LED_2", 0, Pins("T3"), IOStandard("lvttl")),
|
||||
("SBUS_3V3_RSTs", 0, Pins("U2"), IOStandard("lvttl")),
|
||||
("SBUS_3V3_SELs", 0, Pins("K6"), IOStandard("lvttl")),
|
||||
("SBUS_3V3_INT1s", 0, Pins("R5"), IOStandard("lvttl")), # moved
|
||||
("SBUS_3V3_INT2s", 0, Pins("H15"), IOStandard("lvttl")), # added
|
||||
("SBUS_3V3_INT3s", 0, Pins("R3"), IOStandard("lvttl")), # added
|
||||
("SBUS_3V3_INT4s", 0, Pins("N5"), IOStandard("lvttl")), # added
|
||||
("SBUS_3V3_INT5s", 0, Pins("L5"), IOStandard("lvttl")), # added
|
||||
("SBUS_3V3_INT6s", 0, Pins("V2"), IOStandard("lvttl")), # added
|
||||
#("SBUS_3V3_INT7s", 0, Pins("N5"), IOStandard("lvttl")),
|
||||
("SBUS_3V3_PPRD", 0, Pins("N6"), IOStandard("lvttl")),
|
||||
("SBUS_OE", 0, Pins("P5"), IOStandard("lvttl")),
|
||||
("SBUS_3V3_ACKs", 0, Pins("M6 L6 N4"), IOStandard("lvttl")),
|
||||
("SBUS_3V3_SIZ", 0, Pins("T6 U3 V1"), IOStandard("lvttl")), # 0 moved
|
||||
("SBUS_3V3_D", 0, Pins("J18 K16 J17 K15 K13 J15 J13 J14 H14 H17 G14 G17 G16 G18 H16 F18 F16 E18 F15 D18 E17 G13 D17 F13 F14 E16 E15 C17 C16 A18 B18 C15"), IOStandard("lvttl")),
|
||||
("SBUS_3V3_PA", 0, Pins("B16 B17 D14 C14 D12 A16 A15 B14 B13 B12 C12 A14 A13 B11 A11 M4 R2 M3 P2 M2 N2 K5 N1 L4 M1 L3 L1 K3"), IOStandard("lvttl")),
|
||||
]
|
||||
|
||||
# reusing the UART pins !!!
|
||||
_usb_io_v1_0 = [
|
||||
("usb", 0,
|
||||
Subsignal("dp", Pins("V9")), # Serial TX
|
||||
Subsignal("dm", Pins("U9")), # Serial RX
|
||||
IOStandard("LVCMOS33"))
|
||||
]
|
||||
|
||||
# Connectors ---------------------------------------------------------------------------------------
|
||||
|
||||
_connectors_v1_0 = [
|
||||
]
|
||||
_connectors_v1_2 = [
|
||||
("P1", "T8 U6 P3 P4 T1 U4 R1 T3"),
|
||||
]
|
||||
|
||||
# Platform -----------------------------------------------------------------------------------------
|
||||
|
||||
class Platform(XilinxPlatform):
|
||||
default_clk_name = "clk48"
|
||||
default_clk_period = 1e9/48e6
|
||||
|
||||
def __init__(self, variant="ztex2.13a", version="V1.0"):
|
||||
device = {
|
||||
"ztex2.13a": "xc7a35tcsg324-1",
|
||||
"ztex2.13b": "xc7a50tcsg324-1", #untested
|
||||
"ztex2.13b2": "xc7a50tcsg324-1", #untested
|
||||
"ztex2.13c": "xc7a75tcsg324-2", #untested
|
||||
"ztex2.13d": "xc7a100tcsg324-2" #untested
|
||||
}[variant]
|
||||
sbus_io = {
|
||||
"V1.0" : _sbus_io_v1_0,
|
||||
"V1.2" : _sbus_io_v1_2,
|
||||
}[version]
|
||||
sbus_sbus = {
|
||||
"V1.0" : _sbus_sbus_v1_0,
|
||||
"V1.2" : _sbus_sbus_v1_2,
|
||||
}[version]
|
||||
connectors = {
|
||||
"V1.0" : _connectors_v1_0,
|
||||
"V1.2" : _connectors_v1_2,
|
||||
}[version]
|
||||
|
||||
XilinxPlatform.__init__(self, device, _io, connectors, toolchain="vivado")
|
||||
self.add_extension(sbus_io)
|
||||
self.add_extension(sbus_sbus)
|
||||
|
||||
self.toolchain.bitstream_commands = \
|
||||
["set_property BITSTREAM.CONFIG.SPI_32BIT_ADDR No [current_design]",
|
||||
"set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 2 [current_design]",
|
||||
"set_property BITSTREAM.CONFIG.CONFIGRATE 66 [current_design]",
|
||||
"set_property BITSTREAM.GENERAL.COMPRESS true [current_design]",
|
||||
"set_property BITSTREAM.GENERAL.CRC DISABLE [current_design]",
|
||||
"set_property STEPS.SYNTH_DESIGN.ARGS.RETIMING true [get_runs synth_1]",
|
||||
"set_property CONFIG_VOLTAGE 3.3 [current_design]",
|
||||
"set_property CFGBVS VCCO [current_design]"
|
||||
# , "set_property STEPS.SYNTH_DESIGN.ARGS.DIRECTIVE AreaOptimized_high [get_runs synth_1]"
|
||||
]
|
||||
|
||||
def create_programmer(self):
|
||||
bscan_spi = "bscan_spi_xc7a35t.bit"
|
||||
return OpenOCD("openocd_xc7_ft2232.cfg", bscan_spi) #FIXME
|
||||
|
||||
def do_finalize(self, fragment):
|
||||
XilinxPlatform.do_finalize(self, fragment)
|
||||
#self.add_period_constraint(self.lookup_request("clk48", loose=True), 1e9/48e6)
|
||||
9
sbus-to-ztex-gateware/README.md
Normal file
9
sbus-to-ztex-gateware/README.md
Normal file
@ -0,0 +1,9 @@
|
||||
## Current status
|
||||
|
||||
2021-03-21: The adapter board seems to work fine in two different SS20. Currently the embedded PROM code exposes three devices in the FPGA:
|
||||
|
||||
* "RDOL,cryptoengine": exposes a (way too large) polynomial multiplier to implement GCM mode and a AES block. Currently used to implement DMA-based acceleration of AES-256-CBC through /dev/crypto. Unfortunately OpenSSL doesn't support AES-256-GCM in the cryptodev engine, and disagree with NetBSD's /dev/crypto on how to implement AES-256-CTR. And the default SSH cannot use cryptodev, it closes all file descriptors after cryptodev has opened /dev/crypto... still WiP.
|
||||
|
||||
* "RDOL,trng": exposes a 5 MHz counter (didn't realize the SS20 already had a good counter) and a so-far-not-true TRNG (implemented by a PRNG). The 'true' random generators I've found make Vivado screams very loudly when synthesizing... anyway both works fine in NetBSD 9.0 as a timecounter and an entropy source (which a PRNG really isn't, I know). still WiP.
|
||||
|
||||
* "RDOL,sdcard": trying to expose the micro-sd card slot as a storage device, at first using SPI mode. So far reading seems to work, and NetBSD can see a Sun disklabel on the micro-sd card if it has been partitioned that way. Mounting a FAT filesystem read-only now works (with very little testing as of yet). Writing not working yet. Very much WiP.
|
||||
Loading…
x
Reference in New Issue
Block a user