mirror of
https://github.com/mist-devel/mist-board.git
synced 2026-01-30 13:06:45 +00:00
732 lines
18 KiB
C++
732 lines
18 KiB
C++
// TODO: include real tos.c
|
|
|
|
#include "Vdma.h"
|
|
#include "verilated.h"
|
|
#include "verilated_vcd_c.h"
|
|
|
|
Vdma* top = NULL;
|
|
VerilatedVcdC* tfp = NULL;
|
|
|
|
double time_ns = 0;
|
|
|
|
#define MEMBASE 0xfc0000
|
|
#define MEMSIZE 256*1024
|
|
unsigned char mem[MEMSIZE];
|
|
|
|
#define MHZ2NS(a) (1000000000.0/(a))
|
|
#define CLK (8000000.0)
|
|
|
|
void hexdump(void *data, int size) {
|
|
int i, b2c, n=0;
|
|
char *ptr = (char*)data;
|
|
|
|
if(!size) return;
|
|
|
|
while(size>0) {
|
|
printf(" %04x: ", n);
|
|
b2c = (size>16)?16:size;
|
|
for(i=0;i<b2c;i++) printf("%02x ", 0xff&ptr[i]);
|
|
printf(" ");
|
|
for(i=0;i<(16-b2c);i++) printf(" ");
|
|
for(i=0;i<b2c;i++) printf("%c", isprint(ptr[i])?ptr[i]:'.');
|
|
printf("\n");
|
|
ptr += b2c;
|
|
size -= b2c;
|
|
n += b2c;
|
|
}
|
|
}
|
|
|
|
unsigned long cpu_read_addr = 0;
|
|
unsigned short cpu_read_data;
|
|
|
|
unsigned long cpu_write_addr = 0;
|
|
unsigned short cpu_write_data;
|
|
|
|
void eval(void) {
|
|
static int last_clk = 0;
|
|
|
|
// evaluate recent changes
|
|
top->eval();
|
|
tfp->dump(time_ns);
|
|
|
|
// eval on negedge of clk
|
|
if(!top->clk && last_clk) {
|
|
|
|
// check if someone wants to read
|
|
if(top->ram_read) {
|
|
unsigned short data = 0;
|
|
unsigned long addr = top->ram_addr<<1;
|
|
unsigned char *ptr = mem+addr-MEMBASE;
|
|
|
|
if((addr >= MEMBASE) && (addr < MEMBASE+MEMSIZE))
|
|
data = 256*ptr[0] + ptr[1];
|
|
else
|
|
printf("Reading outside range: %lx\n", addr);
|
|
|
|
// printf(" RAM_READ(%lx)=%x\n", addr, data);
|
|
top->ram_din = data;
|
|
}
|
|
|
|
// check if someone wants to write
|
|
if(top->ram_write) {
|
|
unsigned long addr = top->ram_addr<<1;
|
|
unsigned short data =
|
|
((top->ram_dout & 0xff)<<8) | ((top->ram_dout & 0xff00)>>8);
|
|
|
|
// printf(" RAM_WRITE(%lx, %x)\n", addr, top->ram_dout);
|
|
|
|
if((addr >= MEMBASE) && (addr < MEMBASE+MEMSIZE))
|
|
*(unsigned short*)(mem+addr-MEMBASE) = data;
|
|
else
|
|
printf("Writing outside range: %lx\n", addr);
|
|
}
|
|
}
|
|
last_clk = top->clk;
|
|
}
|
|
|
|
// advance time and create valid 8 Mhz clock and signals
|
|
// derived from it
|
|
void wait_ns(double n) {
|
|
static int clk_time = 0;
|
|
|
|
eval();
|
|
|
|
// check if next clk event is within waiting period
|
|
while(clk_time <= n) {
|
|
time_ns += clk_time; // advance time to next clk event
|
|
n -= clk_time; // reduce remainung waiting time
|
|
|
|
// process change on clk
|
|
top->clk = !top->clk;
|
|
|
|
// cpu reads on falling clock edge
|
|
if((!top->clk) && (top->bus_cycle == 0)) {
|
|
// read access in progress?
|
|
if(top->cpu_sel && top->cpu_rw) {
|
|
cpu_read_data = top->cpu_dout;
|
|
cpu_read_addr = 0;
|
|
}
|
|
}
|
|
|
|
if(top->clk) {
|
|
// do everything that's supposed to happen on the rising
|
|
// edge of clk
|
|
top->bus_cycle = (top->bus_cycle + 1)&3;
|
|
top->cpu_sel = 0;
|
|
|
|
if(top->bus_cycle == 0) {
|
|
if(cpu_read_addr) {
|
|
// perform cpu read access
|
|
top->cpu_sel = (cpu_read_addr & ~0xf) == 0xff8600;
|
|
top->cpu_addr = (cpu_read_addr & 0x0f)>>1;
|
|
top->cpu_rw = 1;
|
|
top->cpu_uds = top->cpu_lds = 0;
|
|
}
|
|
|
|
// perform cpu write access
|
|
if(cpu_write_addr) {
|
|
top->cpu_sel = (cpu_write_addr & ~0xf) == 0xff8600;
|
|
top->cpu_addr = (cpu_write_addr & 0x0f)>>1;
|
|
top->cpu_rw = 0;
|
|
top->cpu_din = cpu_write_data;
|
|
top->cpu_uds = top->cpu_lds = 0;
|
|
cpu_write_addr = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
eval();
|
|
|
|
clk_time = MHZ2NS(CLK)/2; // next clk change in 62.5ns
|
|
}
|
|
|
|
// next event is when done waiting
|
|
time_ns += n; // advance time
|
|
clk_time -= n;
|
|
}
|
|
|
|
void wait_us(double n) {
|
|
wait_ns(n * 1000.0);
|
|
}
|
|
|
|
void wait_ms(double n) {
|
|
wait_us(n * 1000.0);
|
|
}
|
|
|
|
void cpu_write(unsigned long addr, unsigned short data) {
|
|
cpu_write_addr = addr;
|
|
cpu_write_data = data;
|
|
wait_us(1); // wait two 2MHz system cycles
|
|
}
|
|
|
|
unsigned short cpu_read(unsigned long addr) {
|
|
cpu_read_addr = addr;
|
|
wait_us(1); // wait two 2MHz system cycles
|
|
return cpu_read_data;
|
|
}
|
|
|
|
#define SPI_CLK 24000000.0
|
|
#define SPI_CLK_NS MHZ2NS(SPI_CLK)
|
|
|
|
// send a byte over spi
|
|
unsigned char SPI(unsigned char byte) {
|
|
unsigned char bit;
|
|
unsigned char retval = 0;
|
|
|
|
// spi at 24Mhz: complete cycle = 41.6666ns
|
|
|
|
// data has to be stable on pos edge of sck
|
|
for(bit=0;bit<8;bit++) {
|
|
wait_ns(SPI_CLK_NS/4);
|
|
top->sck = 0;
|
|
wait_ns(SPI_CLK_NS/4);
|
|
top->sdi = (byte & (0x80>>bit))?1:0;
|
|
retval = (retval << 1) | (top->sdo?1:0);
|
|
wait_ns(SPI_CLK_NS/4);
|
|
top->sck = 1;
|
|
wait_ns(SPI_CLK_NS/4);
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
#define SPI_WRITE(a) SPI(a)
|
|
|
|
void EnableFpga(void) {
|
|
wait_ns(100);
|
|
top->ss = 0;
|
|
wait_ns(100);
|
|
}
|
|
|
|
void DisableFpga(void) {
|
|
wait_ns(200);
|
|
top->ss = 1;
|
|
wait_ns(10);
|
|
}
|
|
|
|
// ------- routines takes from firmware tos.c ----------------
|
|
#define MIST_SET_ADDRESS 0x01
|
|
#define MIST_WRITE_MEMORY 0x02
|
|
#define MIST_READ_MEMORY 0x03
|
|
#define MIST_SET_CONTROL 0x04
|
|
#define MIST_GET_DMASTATE 0x05 // reads state of dma and floppy controller
|
|
#define MIST_ACK_DMA 0x06 // acknowledge a dma command
|
|
#define MIST_SET_VADJ 0x09
|
|
#define MIST_NAK_DMA 0x0a // reject a dma command
|
|
|
|
static void mist_memory_set_address(unsigned long a, unsigned char s, char rw) {
|
|
a |= rw?0x1000000:0;
|
|
a >>= 1;
|
|
|
|
EnableFpga();
|
|
SPI(MIST_SET_ADDRESS);
|
|
SPI(s);
|
|
SPI((a >> 16) & 0xff);
|
|
SPI((a >> 8) & 0xff);
|
|
SPI((a >> 0) & 0xff);
|
|
DisableFpga();
|
|
}
|
|
|
|
static void mist_memory_write(char *data, unsigned long words) {
|
|
|
|
EnableFpga();
|
|
SPI(MIST_WRITE_MEMORY);
|
|
|
|
while(words--) {
|
|
SPI_WRITE(*data++);
|
|
SPI_WRITE(*data++);
|
|
}
|
|
|
|
DisableFpga();
|
|
}
|
|
|
|
static void mist_memory_read(char *data, unsigned long words) {
|
|
|
|
EnableFpga();
|
|
SPI(MIST_READ_MEMORY);
|
|
|
|
// transmitted bytes must be multiple of 2 (-> words)
|
|
while(words--) {
|
|
*data++ = SPI(0);
|
|
*data++ = SPI(0);
|
|
// printf("SPI RX: %02x %02x\n", *(data-2), *(data-1));
|
|
}
|
|
|
|
DisableFpga();
|
|
}
|
|
|
|
void tos_set_video_adjust(unsigned char a, unsigned char b) {
|
|
EnableFpga();
|
|
SPI(MIST_SET_VADJ);
|
|
SPI(a);
|
|
SPI(b);
|
|
DisableFpga();
|
|
}
|
|
|
|
static void mist_set_control(unsigned long ctrl) {
|
|
EnableFpga();
|
|
SPI(MIST_SET_CONTROL);
|
|
SPI((ctrl >> 24) & 0xff);
|
|
SPI((ctrl >> 16) & 0xff);
|
|
SPI((ctrl >> 8) & 0xff);
|
|
SPI((ctrl >> 0) & 0xff);
|
|
DisableFpga();
|
|
}
|
|
|
|
static void mist_get_dmastate(unsigned char *buffer) {
|
|
int i;
|
|
|
|
EnableFpga();
|
|
SPI(MIST_GET_DMASTATE);
|
|
for(i=0;i<16;i++)
|
|
buffer[i] = SPI(0);
|
|
DisableFpga();
|
|
|
|
// printf(" IO controllers view on DMA state:\n");
|
|
// hexdump(buffer, 16);
|
|
|
|
// check if acsi is busy
|
|
if(buffer[15] & 1)
|
|
printf("ACSI busy flag set\n");
|
|
// handle_acsi(buffer);
|
|
|
|
// check if fdc is busy
|
|
if(buffer[8] & 1) {
|
|
printf("FDC busy flag set\n");
|
|
printf("FDC CMD = %x\n", buffer[4]);
|
|
printf("FDC TRK = %x\n", buffer[5]);
|
|
printf("FDC SEC = %x\n", buffer[6]);
|
|
printf("FDC DAT = %x\n", buffer[7]);
|
|
printf("FDC FLG = %x\n", buffer[8]);
|
|
|
|
// handle_fdc(buffer);
|
|
}
|
|
}
|
|
|
|
static void spi_noise() {
|
|
int i, cnt = random()&15;
|
|
for(i=0;i<cnt;i++)
|
|
SPI(random());
|
|
}
|
|
|
|
void dma_address_verify(unsigned long a, unsigned char s, char rw) {
|
|
unsigned char buffer[16];
|
|
|
|
wait_us(5);
|
|
|
|
// check that address has advanced correctly
|
|
if((top->ram_addr<<1) != a) {
|
|
printf("ERROR: DMA address is %x, should be %lx\n",
|
|
top->ram_addr<<1, a);
|
|
tfp->close();
|
|
exit(0);
|
|
}
|
|
|
|
if(top->v__DOT__dma_scnt != s) {
|
|
printf(" ERROR: Sector count is %d, should be %d\n",
|
|
top->v__DOT__dma_scnt, s);
|
|
tfp->close();
|
|
exit(0);
|
|
}
|
|
|
|
// check that direction matches
|
|
if(top->v__DOT__dma_direction_out != rw) {
|
|
printf(" ERROR: Direction is incorrect, is %d, should be %d\n",
|
|
top->v__DOT__dma_direction_out, rw);
|
|
tfp->close();
|
|
exit(0);
|
|
}
|
|
|
|
// cpu only works if system is not in reset
|
|
if(!top->reset) {
|
|
unsigned long cpu_dma_addr =
|
|
(cpu_read(0xFF8609)<<16) | (cpu_read(0xFF860B)<<8) | cpu_read(0xFF860D);
|
|
|
|
// check that dma address visible to cpu matches
|
|
if(cpu_dma_addr != a) {
|
|
printf("ERROR: cpu visible DMA address is %lx, should be %lx\n",
|
|
cpu_dma_addr, a);
|
|
tfp->close();
|
|
exit(0);
|
|
}
|
|
|
|
// enable access to sector count register
|
|
cpu_write(0xFF8606, 0x10);
|
|
|
|
unsigned char cpu_dma_scnt = cpu_read(0xFF8604);
|
|
if(cpu_dma_scnt != s) {
|
|
printf(" ERROR: CPU visible sector count is %d, should be %d\n",
|
|
cpu_dma_scnt, s);
|
|
tfp->close();
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
// and check address and sector count encoded in dma state
|
|
mist_get_dmastate(buffer);
|
|
|
|
// printf(" FIFO: r=%d, w=%d\n", (buffer[10]>>4)&0x0f, buffer[10]&0x0f);
|
|
|
|
unsigned long ioc_dma_addr =
|
|
(buffer[0] << 16) + (buffer[1] << 8) + (buffer[2]&0xfe);
|
|
|
|
if(ioc_dma_addr != a) {
|
|
printf("ERROR: io controller visible DMA address is %lx, should be %lx\n",
|
|
ioc_dma_addr, a);
|
|
tfp->close();
|
|
exit(0);
|
|
}
|
|
|
|
if(buffer[3] != s) {
|
|
printf(" ERROR: IO controller visible sector count is %d, should be %d\n",
|
|
buffer[3], s);
|
|
tfp->close();
|
|
exit(0);
|
|
}
|
|
|
|
printf(" dir %s, scnt %d, addr $%lx ok. CPU %s\n",
|
|
rw?"out":"in", s, a, top->reset?"ignored":"ok");
|
|
}
|
|
|
|
void port_test() {
|
|
printf("== IO controller port test ==\n");
|
|
|
|
// test some config/setup routines
|
|
tos_set_video_adjust(0x12, 0x34);
|
|
if(top->video_adj != 0x1234) {
|
|
printf("ERROR: setting vadj failed\n");
|
|
tfp->close();
|
|
exit(1);
|
|
} else
|
|
printf(" Video adjustment ok\n");
|
|
|
|
mist_set_control(0x12345678);
|
|
if(top->ctrl_out != 0x12345678) {
|
|
printf("ERROR: setting control failed\n");
|
|
tfp->close();
|
|
exit(1);
|
|
} else
|
|
printf(" Control register write ok\n");
|
|
}
|
|
|
|
// $FF8606|word |DMA mode/status BIT 8 7 6 . 4 3 2 1 .|W
|
|
// | |0 - read FDC/HDC,1 - write ---------' | | | | | | | |
|
|
// | |0 - HDC access,1 - FDC access --------' | | | | | | |
|
|
// | |0 - DMA on,1 - no DMA ------------------' | | | | | |
|
|
// | |Reserved ---------------------------------' | | | | |
|
|
// | |0 - FDC reg,1 - sector count reg -----------' | | | |
|
|
// | |0 - FDC access,1 - HDC access ----------------' | | |
|
|
// | |0 - pin A1 low, 1 - pin A1 high ----------------' | |
|
|
// | |0 - pin A0 low, 1 - pin A0 high ------------------' |
|
|
|
|
void dma_mode_dump() {
|
|
printf(">> DMA mode = %x\n", top->v__DOT__dma_mode);
|
|
|
|
if(!(top->v__DOT__dma_mode & 0x100))
|
|
printf(" - DMA read (%s)\n", top->v__DOT__dma_direction_out?"write":"read");
|
|
else
|
|
printf(" - DMA write (%s)\n", top->v__DOT__dma_direction_out?"write":"read");
|
|
if(!(top->v__DOT__dma_mode & 0x80)) printf(" - ACSI DMA\n"); else printf(" - FDC DMA\n");
|
|
if(!(top->v__DOT__dma_mode & 0x40)) printf(" - DMA on\n"); else printf(" - DMA off\n");
|
|
if(!(top->v__DOT__dma_mode & 0x10)) printf(" - FDC/ACSI reg\n"); else printf(" - Sector count\n");
|
|
if(!(top->v__DOT__dma_mode & 0x08)) printf(" - FDC access\n"); else printf(" - ACSI access\n");
|
|
printf(" - A1/A0 = %d\n", (top->v__DOT__dma_mode >> 1)&3);
|
|
|
|
// fdc registers
|
|
printf("FDC CMD: %x\n", top->v__DOT__fdc__DOT__cmd);
|
|
printf("FDC TRK: %x\n", top->v__DOT__fdc__DOT__track);
|
|
printf("FDC SEC: %x\n", top->v__DOT__fdc__DOT__sector);
|
|
printf("FDC DAT: %x\n", top->v__DOT__fdc__DOT__data);
|
|
}
|
|
|
|
void dma_cpu_test() {
|
|
unsigned char buffer[16];
|
|
|
|
// ----- now start a dma transfer from the cpu interface -----
|
|
|
|
printf("== Core DMA write test ==\n");
|
|
|
|
dma_mode_dump();
|
|
|
|
// set dma address
|
|
cpu_write(0xFF8609, 0xfc);
|
|
cpu_write(0xFF860B, 0x00);
|
|
cpu_write(0xFF860D, 0x00);
|
|
|
|
// enable access to sector count register
|
|
cpu_write(0xFF8606, 0x10);
|
|
|
|
dma_mode_dump();
|
|
|
|
// write 1 to sector counter register (starts dma on write to io controller)
|
|
cpu_write(0xFF8604, 0x01);
|
|
|
|
dma_mode_dump();
|
|
|
|
// dma transfer itself is done by the io controller
|
|
|
|
#define dmal 0xff860d
|
|
#define dmam 0xff860b
|
|
#define dmah 0xff8609
|
|
|
|
#define fdcc 0xff8604
|
|
#define dmac 0xff8606
|
|
|
|
mist_get_dmastate(buffer);
|
|
|
|
// a2 = dmac, a3 = fdcc
|
|
cpu_write(dmac, 0x82); // *Track register
|
|
dma_mode_dump();
|
|
|
|
printf("current track = %d\n", cpu_read(fdcc)); //* Current track
|
|
cpu_write(fdcc, 0x01);
|
|
printf("current track = %d\n", cpu_read(fdcc)); //* Current track
|
|
|
|
cpu_write(dmac, 0x86); // *Data register
|
|
cpu_write(fdcc, 0x01);
|
|
|
|
mist_get_dmastate(buffer);
|
|
|
|
printf("181:\n");
|
|
cpu_write(dmac, 0x181); // *Data register
|
|
|
|
dma_mode_dump();
|
|
|
|
// move.w #$13,(a3) *Seek command, steprate 3ms
|
|
// bsr comexd
|
|
}
|
|
|
|
void io_write_test(char *data, int size, int chunk_size) {
|
|
printf("== IO controller DMA %d bytes %s write test ==\n",
|
|
size, chunk_size?"chunky":"burst");
|
|
|
|
if(chunk_size) printf(" Chunk size = %d\n", chunk_size);
|
|
|
|
unsigned char scnt = (size+511)/512;
|
|
printf(" Sector count will be %d\n", scnt);
|
|
|
|
// destination address can be set externally
|
|
mist_memory_set_address(MEMBASE, scnt, 0);
|
|
dma_address_verify(MEMBASE, scnt, 0);
|
|
|
|
// data is transferred in 16 bytes chunks
|
|
unsigned long bytes = size & ~0x0f;
|
|
|
|
// initiate dma transfer
|
|
printf(" Sending %d bytes via dma, expecting %lu to arrive ...\n",
|
|
size, bytes);
|
|
|
|
if(chunk_size > 0) {
|
|
int sent = 0;
|
|
char *p = data;
|
|
int s = size;
|
|
while(s) {
|
|
// printf("chunk\n");
|
|
int cs = (s>=chunk_size)?chunk_size:s;
|
|
mist_memory_write(p, cs/2);
|
|
p += chunk_size;
|
|
s -= cs;
|
|
sent += chunk_size;
|
|
// printf("after: sent=%d, rem=%d\n", sent, s);
|
|
|
|
if(s)
|
|
dma_address_verify(MEMBASE+(sent&~15), (s+511)/512, 0);
|
|
}
|
|
} else
|
|
mist_memory_write(data, size/2);
|
|
|
|
wait_us(5);
|
|
|
|
// check that data has arrived in memory
|
|
if(memcmp(data, mem, bytes) != 0) {
|
|
int i=0;
|
|
while(data[i] == (char)(mem[i])) i++;
|
|
|
|
printf("ERROR: dma verify failed at index %d\n", i);
|
|
|
|
hexdump(data, 32);
|
|
hexdump(mem, 32);
|
|
|
|
tfp->close();
|
|
exit(0);
|
|
} else
|
|
printf(" %ld bytes successfully verified\n", bytes);
|
|
|
|
// if transferred bytes is not a multiple of 512, then scnt will not reach 0
|
|
dma_address_verify(MEMBASE+bytes, (bytes&0x1ff)?1:0, 0);
|
|
|
|
// printf(" RAM contents now:\n");
|
|
// hexdump(mem, 48);
|
|
}
|
|
|
|
void io_read_test(char *data, int size, int chunk_size) {
|
|
unsigned char test_rx[size];
|
|
|
|
// inject test data into memory
|
|
memcpy(mem, data, size);
|
|
|
|
// ----- read data back via DMA interface -----
|
|
printf("== IO controller DMA %d bytes %s read test ==\n",
|
|
size, chunk_size?"chunky":"burst");
|
|
|
|
unsigned char scnt = (size+511)/512;
|
|
printf(" Sector count will be %d\n", scnt);
|
|
|
|
// data is transferred in 16 bytes chunks
|
|
// unsigned long bytes = (size+16) & ~0x0f;
|
|
unsigned long bytes = (size+31) & ~0x0f;
|
|
// but never more than scnt allows
|
|
if(bytes > 512*scnt) bytes = 512*scnt;
|
|
|
|
// re-set destination address as it has advanced during
|
|
// the DMA transfer
|
|
// address bit 24 == 1 -> dma read
|
|
mist_memory_set_address(MEMBASE, scnt, 1);
|
|
|
|
// initiate dma transfer
|
|
printf(" Receiving %d bytes via dma, expecting %d bytes to be read ...\n",
|
|
size, bytes);
|
|
|
|
// A whole turbo dma read of 16 bytes takes 8*250ns = 2us.
|
|
// We can start earlier since only one word has to be arrived
|
|
// in the fifo for us to read.
|
|
wait_us(1);
|
|
|
|
if(chunk_size > 0) {
|
|
spi_noise();
|
|
|
|
int mb = MEMBASE;
|
|
char *p = (char*)test_rx;
|
|
int s = size;
|
|
while(s) {
|
|
int cs = (s>=chunk_size)?chunk_size:s;
|
|
mist_memory_read(p, cs/2);
|
|
p += chunk_size;
|
|
s -= cs;
|
|
mb+=512;
|
|
dma_address_verify(mb+(s?16:0), s/512, 1);
|
|
}
|
|
} else
|
|
mist_memory_read((char*)test_rx, size/2);
|
|
|
|
// hexdump(test_rx, sizeof(test_rx));
|
|
|
|
// check that data has arrived in buffer
|
|
if(memcmp(test_rx, mem, size) != 0) {
|
|
int i=0;
|
|
while(test_rx[i] == mem[i]) i++;
|
|
|
|
printf("ERROR: dma verify failed at index %d\n", i);
|
|
|
|
hexdump(mem, 48);
|
|
hexdump(test_rx, 48);
|
|
|
|
tfp->close();
|
|
exit(0);
|
|
} else
|
|
printf(" %ld bytes successfully verified\n", size);
|
|
|
|
// the DMA will reload after this, so wait some time for it to get
|
|
// into a stable (non-empty) state again
|
|
wait_us(5);
|
|
|
|
dma_address_verify(MEMBASE+bytes, (bytes&0x1ff)?1:0, 1);
|
|
}
|
|
|
|
int main(int argc, char **argv, char **env) {
|
|
Verilated::commandArgs(argc, argv);
|
|
// init top verilog instance
|
|
top = new Vdma;
|
|
|
|
srandom(time(NULL));
|
|
|
|
// init trace dump
|
|
Verilated::traceEverOn(true);
|
|
tfp = new VerilatedVcdC;
|
|
top->trace (tfp, 99);
|
|
tfp->open ("dma.vcd");
|
|
|
|
// initialize system inputs
|
|
top->clk = 1;
|
|
top->reset = 1;
|
|
|
|
// enabling the turbo doesn't make much sense as the dma in non-turbo
|
|
// at 2Mcycles/sec can transfer 4MBytes/sec is always faster than the
|
|
// SPI at 24Mhz doing 3MBytes/sec
|
|
top->turbo = 0;
|
|
|
|
// init cpu interface
|
|
top->cpu_sel <= 0;
|
|
|
|
// init spi
|
|
top->sdi = 1;
|
|
top->ss = 1;
|
|
top->sck = 1;
|
|
|
|
// floppy
|
|
top->drv_sel = 3; // no drive delected
|
|
top->drv_side = 0;
|
|
top->fdc_wr_prot = 0;
|
|
|
|
wait_us(1);
|
|
|
|
port_test();
|
|
|
|
unsigned char test[2048];
|
|
int i;
|
|
#if 1
|
|
for(i=0;i<sizeof(test);i++) test[i] = random();
|
|
#else
|
|
for(i=0;i<sizeof(test);i++) test[i] = i;
|
|
#endif
|
|
|
|
// small chunks (as e.q. inquiry would do)
|
|
io_write_test((char*)test, 100, 20);
|
|
|
|
#if 0
|
|
// multiple of 16 but less than 512
|
|
io_write_test((char*)test, 32, 0);
|
|
io_read_test((char*)test, 32, 0);
|
|
|
|
// not multiple of 16
|
|
io_write_test((char*)test, 40, 0);
|
|
io_read_test((char*)test, 40, 0);
|
|
|
|
if(!top->v__DOT__dma_in_progress) {
|
|
printf("ERROR: DMA is expected to still be active after incomplete transfer\n");
|
|
tfp->close();
|
|
exit(1);
|
|
}
|
|
|
|
// stop uncompleted DMA
|
|
mist_memory_set_address(0,0,0);
|
|
|
|
if(top->v__DOT__dma_in_progress) {
|
|
printf("ERROR: DMA is expected to be stopped now\n");
|
|
tfp->close();
|
|
exit(1);
|
|
}
|
|
|
|
// multiple of 16 and multiple of 512
|
|
io_write_test((char*)test, sizeof(test), 0);
|
|
io_read_test((char*)test, sizeof(test), 0);
|
|
|
|
// leave reset
|
|
top->reset = 0;
|
|
|
|
// multiple of 16 and multiple of 512 in chunks
|
|
io_write_test((char*)test, sizeof(test), 512);
|
|
io_read_test((char*)test, sizeof(test), 512);
|
|
#endif
|
|
|
|
top->reset = 0;
|
|
wait_ns(100);
|
|
|
|
// dma_cpu_test();
|
|
|
|
tfp->close();
|
|
|
|
exit(0);
|
|
}
|
|
|