kopia lustrzana https://github.com/maccasoft/z80-tools
260 wiersze
7.1 KiB
Java
260 wiersze
7.1 KiB
Java
/*
|
|
* Copyright (c) 2018-19 Marco Maccaferri and others.
|
|
*
|
|
* All rights reserved. This program and the accompanying materials
|
|
* are made available under the terms of the Eclipse Public License v1.0
|
|
* which accompanies this distribution, and is available at
|
|
* http://www.eclipse.org/legal/epl-v10.html
|
|
*/
|
|
|
|
package com.maccasoft.tools;
|
|
|
|
import java.io.File;
|
|
import java.io.FileInputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.RandomAccessFile;
|
|
|
|
import z80core.MemIoOps;
|
|
import z80core.Z80;
|
|
|
|
public class Machine extends MemIoOps {
|
|
|
|
public final static int SIOA_C = 0x80;
|
|
public final static int SIOA_D = 0x81;
|
|
public final static int SIOB_C = 0x82;
|
|
public final static int SIOB_D = 0x83;
|
|
|
|
public final static int CF_DATA = 0x10;
|
|
public final static int CF_FEATURES = 0x11;
|
|
public final static int CF_ERROR = 0x11;
|
|
public final static int CF_SECCOUNT = 0x12;
|
|
public final static int CF_SECTOR = 0x13;
|
|
public final static int CF_CYL_LOW = 0x14;
|
|
public final static int CF_CYL_HI = 0x15;
|
|
public final static int CF_HEAD = 0x16;
|
|
public final static int CF_STATUS = 0x17;
|
|
public final static int CF_COMMAND = 0x17;
|
|
public final static int CF_LBA0 = 0x13;
|
|
public final static int CF_LBA1 = 0x14;
|
|
public final static int CF_LBA2 = 0x15;
|
|
public final static int CF_LBA3 = 0x16;
|
|
|
|
public final static int CF_READ_SEC = 0x20;
|
|
public final static int CF_WRITE_SEC = 0x30;
|
|
|
|
boolean page;
|
|
byte[] rom;
|
|
byte[] ram;
|
|
|
|
byte cfCommand;
|
|
byte[] cfLBA = new byte[4];
|
|
File cfFile;
|
|
RandomAccessFile cf;
|
|
|
|
Z80 proc;
|
|
Thread thread;
|
|
double clockNs;
|
|
|
|
public Machine() {
|
|
rom = new byte[16384];
|
|
ram = new byte[65536];
|
|
|
|
clockNs = 1000.0 / 7.3728;
|
|
|
|
proc = new Z80(this, null);
|
|
|
|
thread = new Thread(new Runnable() {
|
|
|
|
@Override
|
|
public void run() {
|
|
Machine.this.run();
|
|
}
|
|
});
|
|
}
|
|
|
|
public void setRom(int address, File file) throws IOException {
|
|
InputStream is = new FileInputStream(file);
|
|
is.read(rom, address, rom.length - address);
|
|
is.close();
|
|
}
|
|
|
|
public void setRom(int address, byte[] rom) throws IOException {
|
|
System.arraycopy(rom, 0, this.rom, address, Math.min(this.rom.length - address, rom.length));
|
|
}
|
|
|
|
public void setClock(double freq) {
|
|
clockNs = 1000.0 / freq;
|
|
}
|
|
|
|
public void setCompactFlash(File file) {
|
|
this.cfFile = file;
|
|
}
|
|
|
|
public void start() {
|
|
try {
|
|
if (cfFile != null) {
|
|
cf = new RandomAccessFile(cfFile, "rw");
|
|
}
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
thread.start();
|
|
}
|
|
|
|
protected void run() {
|
|
long ns = System.nanoTime();
|
|
|
|
while (!Thread.interrupted()) {
|
|
synchronized (proc) {
|
|
int runTstates = (int) ((System.nanoTime() - ns) / clockNs);
|
|
if (runTstates >= 4) {
|
|
long prevTstates = tstates;
|
|
while (tstates < (prevTstates + runTstates)) {
|
|
proc.execute();
|
|
}
|
|
ns += (tstates - prevTstates) * clockNs;
|
|
}
|
|
}
|
|
|
|
try {
|
|
Thread.sleep(1L);
|
|
} catch (InterruptedException e) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void reset() {
|
|
synchronized (proc) {
|
|
page = false;
|
|
tstates = 0;
|
|
proc.reset();
|
|
super.reset();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int fetchOpcode(int address) {
|
|
tstates += 4; // 3 clocks to fetch opcode from RAM and 1 execution clock
|
|
if (!page && address < rom.length) {
|
|
return rom[address & 0xFFFF] & 0xff;
|
|
}
|
|
return ram[address & 0xFFFF] & 0xff;
|
|
}
|
|
|
|
@Override
|
|
public int inPort(int port) {
|
|
tstates += 4; // 4 clocks for read byte from bus
|
|
|
|
switch (port & 0xFF) {
|
|
case CF_DATA:
|
|
if (cfCommand == CF_READ_SEC) {
|
|
try {
|
|
if (cf != null) {
|
|
return (byte) cf.read();
|
|
}
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
break;
|
|
case CF_STATUS:
|
|
return 0x40; // CF ready
|
|
case SIOA_C:
|
|
return 0x04; // Always return TX buffer empty
|
|
case SIOB_C:
|
|
return 0x04; // Always return TX buffer empty
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
public void outPort(int port, int value) {
|
|
tstates += 4; // 4 clocks for write byte to bus
|
|
|
|
switch (port & 0xFF) {
|
|
case CF_DATA:
|
|
if (cfCommand == CF_WRITE_SEC) {
|
|
try {
|
|
if (cf != null) {
|
|
cf.write(value & 0xFF);
|
|
}
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
break;
|
|
case CF_COMMAND:
|
|
cfCommand = (byte) value;
|
|
if (cfCommand == CF_WRITE_SEC || cfCommand == CF_READ_SEC) {
|
|
try {
|
|
long addr = ((cfLBA[3] & 0x0F) << 24) | ((cfLBA[2] & 0xFF) << 16) | ((cfLBA[1] & 0xFF) << 8) | (cfLBA[0] & 0xFF);
|
|
if (cf != null) {
|
|
cf.seek(addr << 9);
|
|
}
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
break;
|
|
case CF_LBA0:
|
|
cfLBA[0] = (byte) value;
|
|
break;
|
|
case CF_LBA1:
|
|
cfLBA[1] = (byte) value;
|
|
break;
|
|
case CF_LBA2:
|
|
cfLBA[2] = (byte) value;
|
|
break;
|
|
case CF_LBA3: {
|
|
cfLBA[3] = (byte) value;
|
|
break;
|
|
}
|
|
case 0x38: // ROM page
|
|
page = !page;
|
|
break;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int peek8(int address) {
|
|
tstates += 3; // 3 clocks for read byte from RAM
|
|
if (!page && address < rom.length) {
|
|
return rom[address & 0xFFFF] & 0xff;
|
|
}
|
|
return ram[address & 0xFFFF] & 0xff;
|
|
}
|
|
|
|
@Override
|
|
public void poke8(int address, int value) {
|
|
tstates += 3; // 3 clocks for write byte to RAM
|
|
if (page || address >= rom.length) {
|
|
ram[address & 0xFFFF] = (byte) value;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public long getTstates() {
|
|
return tstates;
|
|
}
|
|
|
|
public void stop() {
|
|
try {
|
|
thread.interrupt();
|
|
} catch (Exception e) {
|
|
// Do nothing
|
|
}
|
|
try {
|
|
if (cf != null) {
|
|
cf.close();
|
|
}
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
}
|