From b739b268ad0acf5c08e7f99737cdf3306f6a77d2 Mon Sep 17 00:00:00 2001 From: Alessandro Abbruzzetti Date: Mon, 27 May 2024 15:50:11 +0200 Subject: [PATCH] First SVP version. --- src/ucesoft/smd/cpu/svp/Register.scala | 138 ++++++++- src/ucesoft/smd/cpu/svp/RegisterType.scala | 2 +- src/ucesoft/smd/cpu/svp/SVP.scala | 324 +++++++++++++++++++++ 3 files changed, 448 insertions(+), 16 deletions(-) create mode 100644 src/ucesoft/smd/cpu/svp/SVP.scala diff --git a/src/ucesoft/smd/cpu/svp/Register.scala b/src/ucesoft/smd/cpu/svp/Register.scala index 97b8833..8f492d2 100644 --- a/src/ucesoft/smd/cpu/svp/Register.scala +++ b/src/ucesoft/smd/cpu/svp/Register.scala @@ -17,6 +17,13 @@ class Register(val rtype:RegisterType): def reset(): Unit = value = 0 + def blindAccessedRead(): Unit = {} + def blindAccessedWrite(): Unit = {} + + def isExternal: Boolean = rtype.ordinal >= PM0.ordinal && rtype.ordinal <= EXT5.ordinal + def isPointer: Boolean = rtype.ordinal >= R0.ordinal && rtype.ordinal <= R7.ordinal + def toExternal: ExternalRegister = this.asInstanceOf[ExternalRegister] + def toPointer: PointerRegister = this.asInstanceOf[PointerRegister] // =========================================================== class BlindRegister extends Register(BLIND): @@ -24,18 +31,112 @@ class BlindRegister extends Register(BLIND): override def write(value: Int): Unit = {} // =========================================================== +class ProgramCounter extends Register(PC): + def getAndInc(): Int = + val pc = value + value += 1 + pc +// =========================================================== -class Accumulator(val AL:Register) extends Register(A): - def write32(value:Int): Unit = +class Accumulator(val AL:Register) extends Register(ACC): + inline private def write32(value:Int): Unit = this.value = value >> 16 AL.write(value & 0xFFFF) - def read32: Int = value << 16 | AL.read + inline private def read32: Int = value << 16 | AL.read + + final def getA: Int = read32 + final def setA(value:Int,st:StatusRegister): Unit = + write32(value) + setNZ(value,st) + final def addA(value: Int, st: StatusRegister): Unit = + write32(read32 + value) + setNZ(value, st) override def reset(): Unit = super.reset() AL.reset() + // affects 32 bits + inline private def setNZ(a:Int,st:StatusRegister): Unit = + if a == 0 then st.setFlag(StatusRegisterFlag.Z) else st.clearFlag(StatusRegisterFlag.Z) + if (a & 0x8000_0000) != 0 then st.setFlag(StatusRegisterFlag.N) else st.clearFlag(StatusRegisterFlag.N) + + final def aluADD(value:Int,st:StatusRegister,_32:Boolean): Unit = + var a = read32 + a += (if _32 then value else value << 16) + write32(a) + setNZ(a,st) + final def aluSUB(value: Int, st: StatusRegister, _32: Boolean): Unit = + var a = read32 + a -= (if _32 then value else value << 16) + write32(a) + setNZ(a,st) + final def aluCMP(value: Int, st: StatusRegister, _32: Boolean): Unit = + var a = read32 + a -= (if _32 then value else value << 16) + setNZ(a,st) + final def aluAND(value: Int, st: StatusRegister, _32: Boolean): Unit = + var a = read32 + a &= (if _32 then value else value << 16) + write32(a) + setNZ(a, st) + final def aluOR(value: Int, st: StatusRegister, _32: Boolean): Unit = + var a = read32 + a |= (if _32 then value else value << 16) + write32(a) + setNZ(a, st) + final def aluXOR(value: Int, st: StatusRegister, _32: Boolean): Unit = + var a = read32 + a ^= (if _32 then value else value << 16) + write32(a) + setNZ(a, st) + final def aluROR(st:StatusRegister): Unit = + var a = read32 + val lsb = a & 1 + a = a >>> 1 | lsb << 31 + write32(a) + setNZ(a, st) + final def aluROL(st: StatusRegister): Unit = + var a = read32 + val msb = a >>> 31 + a = a << 1 | msb + write32(a) + setNZ(a, st) + final def aluSHR(st: StatusRegister): Unit = + var a = read32 + a = a >> 1 + write32(a) + setNZ(a, st) + final def aluSHL(st: StatusRegister): Unit = + var a = read32 + a = a << 1 + write32(a) + setNZ(a, st) + final def aluINC(st: StatusRegister): Unit = + var a = read32 + a += 1 + write32(a) + setNZ(a, st) + final def aluDEC(st: StatusRegister): Unit = + var a = read32 + a -= 1 + write32(a) + setNZ(a, st) + final def aluNEG(st: StatusRegister): Unit = + var a = read32 + a = ~a + write32(a) + setNZ(a, st) + final def aluABS(st: StatusRegister): Unit = + var a = read32 + a = 0x7FFF_FFFF + write32(a) + setNZ(a, st) + +end Accumulator + + // =========================================================== class Stack extends Register(STACK): @@ -78,6 +179,8 @@ enum StatusRegisterFlag(val mask:Int,val shift:Int): case N extends StatusRegisterFlag(0x8000,15) class StatusRegister extends Register(ST): + override def read: Int = + value & ~StatusRegisterFlag.IE.mask def getFlag(f:StatusRegisterFlag): Int = (value & f.mask) >> f.shift def setFlag(f:StatusRegisterFlag,value:Int): Unit = @@ -109,14 +212,15 @@ class P(val X:Register,val Y:Register,st:StatusRegister) extends Register(Regist value // =========================================================== -enum PointerRegisterModifier: - case None, PostIncrementModulo, PostDecrementModulo, PostIncrement, _00, _01, _10, _11 - - def from(ri:Int,mod:Int): PointerRegisterModifier = +object PointerRegisterModifier: + def fromRI(ri: Int, mod: Int): PointerRegisterModifier = if ri == 3 || ri == 7 then PointerRegisterModifier.fromOrdinal(_00.ordinal + (mod & 3)) else PointerRegisterModifier.fromOrdinal(mod & 3) +enum PointerRegisterModifier: + case None, PostIncrementModulo, PostDecrementModulo, PostIncrement, _00, _01, _10, _11 + enum PointerRegisterAddressing: case Direct, Indirect1, Indirect2 @@ -331,9 +435,9 @@ class ExternalRegister(val index:0|1|2|3|4|5,val mem:SVPMemory,val pmc:PMC,val s java.util.Arrays.fill(externalAddress,0) java.util.Arrays.fill(externalAddressIncrement, 0) - def setReadMode(): Unit = + override def blindAccessedRead(): Unit = setMode(R) - def setWriteMode(): Unit = + override def blindAccessedWrite(): Unit = setMode(W) private def setMode(mode:0|1): Unit = @@ -342,8 +446,8 @@ class ExternalRegister(val index:0|1|2|3|4|5,val mem:SVPMemory,val pmc:PMC,val s if mode == W then externalOverwrite = pmc.isOverwriteMode - protected def externalStatusRegisterRead(): Int = 0 - protected def externalStatusRegisterWrite(value:Int): Unit = {} + protected def externalStatusRegisterRead(readByM68K:Boolean): Int = 0 + protected def externalStatusRegisterWrite(value:Int,writeByM68K:Boolean): Unit = {} private def incrementAddress(): Unit = if externalAddressIncrement(R) == SPECIAL_INC then // special increment @@ -352,13 +456,15 @@ class ExternalRegister(val index:0|1|2|3|4|5,val mem:SVPMemory,val pmc:PMC,val s externalAddress(R) += externalAddressIncrement(R) externalAddress(R) &= 0x1F_FFFF - override def read: Int = + override def read: Int = read(readByM68K = false) + + def read(readByM68K:Boolean): Int = if index == 4 || st.getFlag(StatusRegisterFlag.RPL) > 0 then val value = mem.svpExternalRead(externalAddress(R)) incrementAddress() value else - externalStatusRegisterRead() + externalStatusRegisterRead(readByM68K) private def overwrite(value:Int): Int = if externalOverwrite then @@ -380,11 +486,13 @@ class ExternalRegister(val index:0|1|2|3|4|5,val mem:SVPMemory,val pmc:PMC,val s else value - override def write(value:Int): Unit = + override def write(value:Int): Unit = write(value,writeByM68K = false) + + def write(value:Int,writeByM68K:Boolean): Unit = if index == 4 || st.getFlag(StatusRegisterFlag.RPL) > 0 then mem.svpExternalWrite(externalAddress(W),overwrite(value)) incrementAddress() else - externalStatusRegisterWrite(value) + externalStatusRegisterWrite(value,writeByM68K) diff --git a/src/ucesoft/smd/cpu/svp/RegisterType.scala b/src/ucesoft/smd/cpu/svp/RegisterType.scala index 5c8c874..5c19803 100644 --- a/src/ucesoft/smd/cpu/svp/RegisterType.scala +++ b/src/ucesoft/smd/cpu/svp/RegisterType.scala @@ -10,7 +10,7 @@ enum RegisterType: /*00*/BLIND, /*01*/X, /*02*/Y, - /*03*/A, + /*03*/ACC, /*04*/ST, /*05*/STACK, /*06*/PC, diff --git a/src/ucesoft/smd/cpu/svp/SVP.scala b/src/ucesoft/smd/cpu/svp/SVP.scala new file mode 100644 index 0000000..c7b92c4 --- /dev/null +++ b/src/ucesoft/smd/cpu/svp/SVP.scala @@ -0,0 +1,324 @@ +package ucesoft.smd.cpu.svp +import RegisterType.* +import ucesoft.smd.Clock.Clockable +import ucesoft.smd.SMDComponent + +/** + * @author Alessandro Abbruzzetti + * Created on 24/05/2024 18:20 + */ +class SVP(val mem:SVPMemory) extends SMDComponent with Clockable: + override protected val smdComponentName = "SVP" + private inline val A = 0 + private inline val B = 1 + + private inline val SSP160x_WRITTEN_XST_MASK = 1 + private inline val M68K_WRITTEN_A15000_MASK = 2 + + private val RAM = Array( Array.ofDim[Int](256), Array.ofDim[Int](256) ) + + private val pcReg = new ProgramCounter + private val stackReg = new Stack + private val stReg = new StatusRegister + private val xReg = new Register(X) + private val yReg = new Register(X) + private val pReg = new P(xReg,yReg,stReg) + + @volatile private var statusXST = 0 + + private val pmcReg = new PMC + /* + If this register is blind-accessed, it is "dummy programmed", i.e. nothing + happens and PMC is reset to "waiting for address" state. + */ + private val alReg = new Register(AL): + override def blindAccessedRead(): Unit = pmcReg.resetState() + override def blindAccessedWrite(): Unit = pmcReg.resetState() + private val aReg = new Accumulator(alReg) + /* + mapped to a15004 on 68k side: + ???????? ??????10 + 0: set, when SSP160x has written something to XST + (cleared when a15004 is read by 68k) + 1: set, when 68k has written something to a15000 or a15002 + (cleared on PM0 read by SSP160x) + */ + private val pm0Reg = new ExternalRegister(0,mem,pmcReg,stReg): + override protected def externalStatusRegisterRead(readByM68K:Boolean): Int = + val status = statusXST + if readByM68K then + statusXST &= ~SSP160x_WRITTEN_XST_MASK + else + statusXST &= ~M68K_WRITTEN_A15000_MASK + status + /* + Mapped to a15000 and a15002 on 68k side. + Affects PM0 when written to. + */ + private val xstReg = new ExternalRegister(3,mem,pmcReg,stReg): + override protected def externalStatusRegisterWrite(value: Int, writeByM68K: Boolean): Unit = + this.value = value + if writeByM68K then + statusXST |= M68K_WRITTEN_A15000_MASK + else + statusXST |= SSP160x_WRITTEN_XST_MASK + + override protected def externalStatusRegisterRead(readByM68K: Boolean): Int = value + + private val regs = Array( + new BlindRegister, + xReg, + yReg, + aReg, + stReg, + stackReg, + pcReg, + pReg, + pm0Reg, + new ExternalRegister(1,mem,pmcReg,stReg), + new ExternalRegister(2,mem,pmcReg,stReg), + xstReg, + new ExternalRegister(4,mem,pmcReg,stReg), + new ExternalRegister(5,mem,pmcReg,stReg), + pmcReg, + alReg, + new PointerRegister(0,mem,RAM(A),stReg), + new PointerRegister(1,mem,RAM(A),stReg), + new PointerRegister(2,mem,RAM(A),stReg), + new PointerRegister(3,mem,RAM(A),stReg), + new PointerRegister(4,mem,RAM(B),stReg), + new PointerRegister(5,mem,RAM(B),stReg), + new PointerRegister(6,mem,RAM(B),stReg), + new PointerRegister(7,mem,RAM(B),stReg) + ) + private var halted = false + // ====================================================================== + override def reset(): Unit = + regs.foreach(_.reset()) + statusXST = 0 + java.util.Arrays.fill(RAM(A),0) + java.util.Arrays.fill(RAM(B), 0) + + pcReg.write(mem.svpReadIRamRom(0xFC08)) + halted = false + end reset + + private def getPtrReg(i:Int): PointerRegister = regs(R0.ordinal + i).asInstanceOf[PointerRegister] + + final def m68kWriteXST(value:Int): Unit = + xstReg.write(value,writeByM68K = true) + final def m68kReadXST(): Int = xstReg.read(readByM68K = true) + final def m68kReadPM0(): Int = + pm0Reg.read(readByM68K = true) + final def halt(enabled:Boolean): Unit = + halted = enabled + + private def alu(op:Int,operand:Int,_32:Boolean): Unit = + op match + case 1 => aReg.aluSUB(operand,stReg,_32) + case 3 => aReg.aluCMP(operand,stReg,_32) + case 4 => aReg.aluADD(operand,stReg,_32) + case 5 => aReg.aluAND(operand,stReg,_32) + case 6 => aReg.aluOR(operand,stReg,_32) + case 7 => aReg.aluXOR(operand,stReg,_32) + + inline private def getRI(opcode:Int): PointerRegister = + regs(RegisterType.R0.ordinal + ((opcode & 0x200) >> 7 | opcode & 3)).asInstanceOf[PointerRegister] + + inline private def isCondition(cccc:Int,f:Int): Boolean = + cccc match + case 0 => true // always + case 5 => if f == 1 then stReg.isSet(StatusRegisterFlag.Z) else stReg.isClear(StatusRegisterFlag.Z) + case 7 => if f == 1 then stReg.isSet(StatusRegisterFlag.N) else stReg.isClear(StatusRegisterFlag.N) + case x => + println(s"Warning checking unchecked condition: $x") + false + + final def clock(cycles:Long): Unit = + if halted then return + + import RegisterType.* + val opcode = mem.svpReadIRamRom(pcReg.getAndInc()) + + opcode >> 9 match + // ALU + // OP A, s ooo0 0000 0000 rrrr + case op@(0x10|0x30|0x40|0x50|0x60|0x70) => + val s = opcode & 0xF + if s == ACC.ordinal then + alu(op >> 4,aReg.getA,_32 = true) + else if s == P.ordinal then + alu(op >> 4,pReg.multiply(),_32 = true) + else + alu(op >> 4,regs(s).read,_32 = false) + // OP A, (ri) ooo0 001j 0000 mmpp + case op@(0x11|0x31|0x41|0x51|0x61|0x71) => + val ri = getRI(opcode) + val mod = PointerRegisterModifier.fromRI(ri.index,(opcode >> 2) & 3) + alu(opcode >> 4,ri.read(PointerRegisterAddressing.Indirect1,mod),_32 = false) + // OP A, adr ooo0 011j aaaa aaaa + case op@(0x13|0x33|0x43|0x53|0x63|0x73) => + val j = (opcode >> 8) & 1 + alu(opcode >> 4,RAM(j)(opcode & 0xFFFF),_32 = false) + // OPi A, imm ooo0 1000 0000 0000 , iiii iiii iiii iiii + case op@(0x14|0x34|0x44|0x54|0x64|0x74) => + val imm = mem.svpReadIRamRom(pcReg.getAndInc()) + alu(opcode >> 4,imm,_32 = false) + // op A, ((ri)) ooo0 101j 0000 mmpp + case op@(0x15|0x35|0x45|0x55|0x65|0x75) => + val ri = getRI(opcode) + val mod = PointerRegisterModifier.fromRI(ri.index, (opcode >> 2) & 3) + alu(opcode >> 4, ri.read(PointerRegisterAddressing.Indirect2, mod), _32 = false) + // op A, ri ooo1 001j 0000 00pp + case op@(0x19|0x39|0x49|0x59|0x69|0x79) => + val ri = getRI(opcode) + alu(opcode >> 4, ri.read, _32 = false) + // OPi simm ooo1 1000 iiii iiii + case op@(0x1C|0x3C|0x4C|0x5C|0x6C|0x7C) => + alu(opcode >> 4,opcode & 0xFFFF,_32 = false) + // ===================== MOD ============================== + // mod cond, op 1001 000f cccc 0ooo + case 0x48 => + if isCondition((opcode >> 4) & 0xF,(opcode >> 8) & 1) then + opcode & 7 match + case 0 => aReg.aluROR(stReg) + case 1 => aReg.aluROL(stReg) + case 2 => aReg.aluSHR(stReg) + case 3 => aReg.aluSHL(stReg) + case 4 => aReg.aluINC(stReg) + case 5 => aReg.aluDEC(stReg) + case 6 => aReg.aluNEG(stReg) + case 7 => aReg.aluABS(stReg) + // mod f, op 1001 0100 0000 oooo + case 0x4A => + opcode & 0xF match + case 2 => stReg.clearFlag(StatusRegisterFlag.L) + case 3 => stReg.setFlag(StatusRegisterFlag.L) + case 4 => stReg.clearFlag(StatusRegisterFlag.IE) + case 5 => stReg.setFlag(StatusRegisterFlag.IE) + case 8 => stReg.clearFlag(StatusRegisterFlag.OP) + case 9 => stReg.setFlag(StatusRegisterFlag.OP) + case 14 => + stReg.clearFlag(StatusRegisterFlag.IE) + stReg.clearFlag(StatusRegisterFlag.OP) + stReg.clearFlag(StatusRegisterFlag.L) + case 15 => + stReg.setFlag(StatusRegisterFlag.IE) + stReg.setFlag(StatusRegisterFlag.OP) + stReg.setFlag(StatusRegisterFlag.L) + case x => + println(s"Unknown mod f, op: $x") + // ===================== LD =============================== + // ld d, s 0000 0000 dddd ssss + case 0x00 => + if opcode != 0 then // nop + val d = opcode >> 4 + val s = opcode & 0xF + if d == ACC.ordinal && s == P.ordinal then // A <- P + aReg.setA(pReg.multiply(),stReg) + else if d == ACC.ordinal && s == ACC.ordinal then {/* do nothing */}// A <- A + else + val dr = regs(d) + val sr = regs(s) + if d == 0 then + sr.blindAccessedRead() + else if s == 0 then + dr.blindAccessedWrite() + else + dr.write(sr.read) + // ld d, (ri) 0000 001j dddd mmpp + case 0x01 => + val ri = getRI(opcode) + val mod = PointerRegisterModifier.fromRI(ri.index,(opcode >> 2) & 3) + regs((opcode >> 4) & 0xF).write(ri.read(PointerRegisterAddressing.Indirect1,mod)) + // ld (ri), s 0000 010j ssss mmpp + case 0x02 => + val ri = getRI(opcode) + val mod = PointerRegisterModifier.fromRI(ri.index,(opcode >> 2) & 3) + ri.write(PointerRegisterAddressing.Indirect1,mod,regs((opcode >> 4) & 0xF).read) + // ldi d, imm 0000 1000 dddd 0000 , iiii iiii iiii iiii + case 0x04 => + val imm = mem.svpReadIRamRom(pcReg.getAndInc()) + regs((opcode >> 4) & 0xF).write(imm) + // ld d, ((ri)) 0000 101j dddd mmpp + case 0x05 => + val ri = getRI(opcode) + val mod = PointerRegisterModifier.fromRI(ri.index,(opcode >> 2) & 3) + regs((opcode >> 4) & 0xF).write(ri.read(PointerRegisterAddressing.Indirect2,mod)) + // ldi (ri), imm 0000 110j 0000 mmpp , iiii iiii iiii iiii + case 0x06 => + val ri = getRI(opcode) + val mod = PointerRegisterModifier.fromRI(ri.index,(opcode >> 2) & 3) + val imm = mem.svpReadIRamRom(pcReg.getAndInc()) + ri.write(PointerRegisterAddressing.Indirect1,mod,imm) + // ld adr, a 0000 111j aaaa aaaa + case 0x07 => + val j = (opcode >> 8) & 1 + RAM(j)(opcode & 0xFFFF) = aReg.read + // ld d, ri 0001 001j dddd 00pp + case 0x09 => + val ri = getRI(opcode) + val d = (opcode >> 4) & 0xF + if d == 0 then + ri.blindAccessedRead() + else + regs(d).write(ri.read) + // ld ri, s 0001 010j ssss 00pp + case 0x0A => + val ri = getRI(opcode) + val s = (opcode >> 4) & 0xF + if s == 0 then + ri.blindAccessedWrite() + else + ri.write(regs(s).read) + // ldi ri, simm 0001 1jpp iiii iiii + case 0xC|0xD|0xE|0xF => + val ri = regs(R0.ordinal + ((opcode >> 8) & 3)).asInstanceOf[PointerRegister] + ri.write(opcode & 0xFFFF) + // ld d, (a) 0100 1010 dddd 0000 + case 0x25 => + val read = mem.svpReadIRamRom(aReg.read) + regs((opcode >> 4) & 0xF).write(read) + // ===================== CALL/BRA ========================= + // call cond, addr 0100 100f cccc 0000 , aaaa aaaa aaaa aaaa + case 0x24 => + val address = mem.svpReadIRamRom(pcReg.getAndInc()) + if isCondition((opcode >> 4) & 0xF,(opcode >> 8) & 1) then + stackReg.write(pcReg.read) + pcReg.write(address) + // bra cond, addr 0100 110f cccc 0000 , aaaa aaaa aaaa aaaa + case 0x26 => + val address = mem.svpReadIRamRom(pcReg.getAndInc()) + if isCondition((opcode >> 4) & 0xF,(opcode >> 8) & 1) then + pcReg.write(address) + // ===================== MLD/MPYA/MPYS ==================== + // mld (rj), (ri) 1011 0111 nnjj mmii + case 0x5B => + val ri = regs(R0.ordinal + (opcode & 3)).asInstanceOf[PointerRegister] + val mi = PointerRegisterModifier.fromRI(ri.index,(opcode >> 2) & 3) + val rj = regs(R0.ordinal + ((opcode >> 4) & 3) + 4).asInstanceOf[PointerRegister] + val mj = PointerRegisterModifier.fromRI(rj.index,(opcode >> 6) & 3) + aReg.setA(0,stReg) + xReg.write(ri.read(PointerRegisterAddressing.Indirect1,mi)) + yReg.write(rj.read(PointerRegisterAddressing.Indirect1,mj)) + // mpya (rj), (ri) 1001 0111 nnjj mmii + case 0x4B => + val ri = regs(R0.ordinal + (opcode & 3)).asInstanceOf[PointerRegister] + val mi = PointerRegisterModifier.fromRI(ri.index,(opcode >> 2) & 3) + val rj = regs(R0.ordinal + ((opcode >> 4) & 3) + 4).asInstanceOf[PointerRegister] + val mj = PointerRegisterModifier.fromRI(rj.index,(opcode >> 6) & 3) + aReg.addA(pReg.multiply(),stReg) + xReg.write(ri.read(PointerRegisterAddressing.Indirect1,mi)) + yReg.write(rj.read(PointerRegisterAddressing.Indirect1,mj)) + // mpys (rj), (ri) 0011 0111 nnjj mmii + case 0x1B => + val ri = regs(R0.ordinal + (opcode & 3)).asInstanceOf[PointerRegister] + val mi = PointerRegisterModifier.fromRI(ri.index,(opcode >> 2) & 3) + val rj = regs(R0.ordinal + ((opcode >> 4) & 3) + 4).asInstanceOf[PointerRegister] + val mj = PointerRegisterModifier.fromRI(rj.index,(opcode >> 6) & 3) + aReg.addA(-pReg.multiply(),stReg) + xReg.write(ri.read(PointerRegisterAddressing.Indirect1,mi)) + yReg.write(rj.read(PointerRegisterAddressing.Indirect1,mj)) + case x => + println("Unrecognized SVP opcode: %04X".format(x)) + end clock