/** * Set up a DMA transfer. * @param direction the direction of the transfer (DMA_READ or DMA_WRITE) * @param chan the channel * @param addr the address of the buffer * @param size number of bytes to transfer */ void Setup_DMA(enum DMA_Direction direction, int chan, void *addr_, ulong_t size) { uchar_t mode = 0; ulong_t addr = (ulong_t) addr_; /* Make sure parameters are sensible */ KASSERT(direction == DMA_READ || direction == DMA_WRITE); KASSERT(VALID_CHANNEL(chan)); KASSERT(IS_RESERVED(chan)); KASSERT(VALID_MEM(addr, size)); KASSERT(size > 0); /* elaborate because the otherwise working test wouldn't work if the DMA region was precisely 64K page aligned. */ KASSERT0((((addr & 0xffff) == 0 && size <= 65536)) || (size <= (0xffff - (addr & 0xffff))), "DMA region can't cross 64K boundary"); /* Set up transfer mode */ mode |= DMA_MODE_SINGLE; mode |= (direction == DMA_READ) ? DMA_MODE_READ : DMA_MODE_WRITE; mode |= (chan & 3); if (chan == 5) mode |= 0x10; /* nspring testing, make this better if useful. */ Debug("Setup_DMA(%s,%d,%x,%d)\n", direction == DMA_READ ? "DMA_READ" : "DMA_WRITE", chan, addr, size); Debug("Setup_DMA: mode=%02x\n", mode); Debug("DMA_ADDR_REG for channel is %02x\n", DMA_ADDR_REG(chan)); Debug("DMA_PAGE_REG for channel is %02x\n", DMA_PAGE_REG(chan)); Debug("DMA_COUNT_REG for channel is %02x\n", DMA_COUNT_REG(chan)); /* Temporarily mask the DMA channel */ Mask_DMA(chan); /* Write the transfer mode */ Out_Byte(DMA_MODE_REG(chan), mode); /* Clear the byte pointer flip-flop */ Out_Byte(DMA_CLEAR_FF_REG(chan), 0); /* doesn't matter what value is written here */ /* Write the transfer address (LSB, then MSB) */ Out_Byte(DMA_ADDR_REG(chan), addr & 0xFF); Out_Byte(DMA_ADDR_REG(chan), (addr >> 8) & 0xFF); /* Write the page register */ Out_Byte(DMA_PAGE_REG(chan), (addr >> 16) & 0xFF); /* * Write the count (LSB, then MSB) * Note that the count is one less that the number of bytes transferred */ if (chan > 4) { size >>= 1; } /* words not bytes? */
void load_and_simulate(const char *bin_fname) { // Load binary into memory int fd = open(bin_fname, O_RDONLY); if (fd < 0) { fprintf(stderr, "Cannot open file %s\n", bin_fname); exit(-1); } size_t len = lseek(fd, 0, SEEK_END); void *data = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0); if (data == MAP_FAILED) { fprintf(stderr, "Memory map failed\n"); close(fd); exit(-1); } // FIXME:: How big is our memory?? -- 512MB // FIXME:: What is the format of binary? ELF?? -- Just full mem-image // FIXME:: where is the program start address -- at 0x0 // FIXME:: Where to load the binary -- at 0x0 const size_t mem_size = ((size_t)512)*1024*1024; const size_t load_pos = (size_t)0x0; const size_t start_pos = (size_t)0x0; int32_t *mem = (int32_t*)memalign(4096, mem_size); if (!mem) { fprintf(stderr, "Cannot allocate memory\n"); munmap(data, len); close(fd); exit(-1); } // Load data to 0x1000 memcpy(&mem[load_pos], data, len); munmap(data, len); close(fd); #define VALID_MEM(X) \ ((X) >= 0 && (X) <= (mem_size - sizeof(int32_t))) #define VALID_PC(X) \ ((X) >= 0 && (X) <= (mem_size - sizeof(int32_t)*3)) // Start executing -- // All our instructions are subleq A, B, C // From wikipedia: https://en.wikipedia.org/wiki/One_instruction_set_computer // subleq A, B, C: Mem[B] = Mem[B] - Mem[A] // if (Mem[B] <= 0) goto C int32_t pc = (int32_t)start_pos; while (VALID_PC(pc)) { int32_t A = mem[pc]; int32_t B = mem[pc+1]; int32_t C = mem[pc+2]; printf("%8x: %8x %8x %8x: A=%d B=%d\n",pc, A, B, C, VALID_MEM(A)?mem[A]:0, VALID_MEM(B)?mem[B]:0); if (A < 0 || B < 0) { pc = 0; continue; } mem[B] -= mem[A]; if (mem[B] > 0) { pc += 3; } else { pc = C; } } // clean up free(mem); }