/*
*
* achtbit.Command.java
*
* Created on: 06.08.2012
* Author: Christian Wahlmann
* This file is part of achtBit.
*
* achtBit is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* achtBit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with achtBit. If not, see <http://www.gnu.org/licenses/>.
*
*/
package achtbit;
/**
*
* @author christian
*/
public class Command {
// ttt, tt=storage type
// 000 = r,r
// 001 = r,n
// 010 = r,(n)
// 011 = r,(r)
//
// 100 = (n),r
// 101 = (r),r
// 102 = (r),n
// rrrr=dest. register, RRRR=source register
// regF = 0000 0
// regA = 0001 1
// regC = 0010 2
// regB = 0011 3
// regE = 0100 4
// regD = 0101 5
// regL = 0110 6
// regH = 0111 7
// regSpL = 1000 8
// regSpH = 1001 9
//
// regAF = 1010 A
// regBC = 1011 B
// regDE = 1100 C
// regHL = 1101 D
// regSP = 1110 E
// regIX = 1111 F
//
// fff = flag
// true = 000 0
// Z = 001 1
// C = 010 2
// P = 011 3
// NZ = 101 5
// NC = 110 6
// NP = 111 7
// n=constant byte nn=constant word
static final int com_nop=0x00; // 00 00000000
static final int com_hlt=0x01; // 01 00000001
static final int com_clc=0x02; // 02 00000010
static final int com_reti=0x03;// 03 00000011
static final int com_setc=0x04; // 04 00000100
// 05 00000101
// -07 -00000111
static final int com_ld=0x08; // 08+t 00001ttt [rrrrRRRR | 0000rrrr] [n | nn]
static final int com_add=0x10; // 10+t 000100tt [rrrrRRRR | 0000rrrr] [n | nn]
static final int com_adc=0x14; // 14+t 000101tt [rrrrRRRR | 0000rrrr] [n | nn]
static final int com_sub=0x18; // 18+t 000110tt [rrrrRRRR | 0000rrrr] [n | nn]
static final int com_sbc=0x1C; // 1C+t 000111tt [rrrrRRRR | 0000rrrr] [n | nn]
static final int com_mul=0x20; // 20+t 001000tt [rrrrRRRR | 0000rrrr] [n | nn]
static final int com_div=0x24; // 24+t 001001tt [rrrrRRRR | 0000rrrr] [n | nn]
static final int com_and=0x28; // 28+t 001010tt [rrrrRRRR | 0000rrrr] [n | nn]
static final int com_or =0x2C; // 2C+t 001011tt [rrrrRRRR | 0000rrrr] [n | nn]
static final int com_xor=0x30; // 30+t 001100tt [rrrrRRRR | 0000rrrr] [n | nn]
static final int com_cmp=0x34; // 34+t 001101tt [rrrrRRRR | 0000rrrr] [n | nn]
static final int com_mod=0x38; // 38+t 001110tt [rrrrRRRR | 0000rrrr] [n | nn]
// 3C 00111100
//-3f 00111110
static final int com_jp =0x40; // 40+f 01000fff nn
static final int com_call=0x48;// 48+f 01001fff nn
static final int com_jr =0x50; // 50+f 01010fff n
static final int com_ret=0x58; // 58+f 01011fff
static final int com_push=0x60;// 60+r 0110rrrr
static final int com_pop=0x70; // 70+r 0111rrrr
static final int com_shl=0x80; // 80+r 1000rrrr
static final int com_shr=0x90; // 90+r 1001rrrr
static final int com_rhl=0xA0; // A0+r 1010rrrr
static final int com_rhr=0xB0; // B0+r 1011rrrr
static final int com_inc=0xC0; // C0+r 1100rrrr
static final int com_dec=0xD0; // D0+r 1101rrrr
static final int com_in =0xE0; // E0+r 1110rrrr n
static final int com_out=0xF0; // F0+r 1111rrrr n
private int com;
private Storage storage;
private int adress;
public Command(int adress, int com) {
this.adress=adress;
this.com=com;
this.storage=new Storage(0,0,0);
}
public Command(int adress, int com, Storage storage) {
this.adress=adress;
this.com=com;
this.storage=storage;
}
public Command() {
this.adress=Memory.instance().getPC();
this.init();
}
public Command(int adress) {
this.adress=new Integer(adress);
this.init();
}
public void init() {
Memory mem=Memory.instance();
this.com=mem.getByte(this.adress);
this.adress=this.adress+1;
storage=null;
if (com==com_nop || com==com_hlt || com==com_clc || com==com_reti);
else if ((com & 0xf8)==com_ld) {
storage=new Storage(); adress=storage.init(com & 7, this.adress);
com&=0xf8;
}
else if (com>=com_add && com<com_mod+4) {
storage=new Storage(); adress=storage.init(com & 3, this.adress);
com&=0xfc;
}
else if (com>=com_jp && com<=com_ret+8) {
int flags=com & 7;
com&=0xf8;
switch (com) {
case com_jp:
case com_call:
storage=new Storage(Storage.RegisterConstant, mem.getWord(this.adress));
this.adress=this.adress+2;
storage.setFlags(flags);
break;
case com_jr:
storage=new Storage(Storage.RegisterConstant, mem.getByte(this.adress));
this.adress=this.adress+1;
storage.setFlags(flags);
break;
case com_ret:
storage=new Storage(0,0);
storage.setFlags(flags);
break;
}
}
else if (com>=com_push && com<com_dec+16) {
int reg=com&15;
com&=0xf0;
storage=new Storage(Storage.RegisterRegister,reg);
}
else if ((com & 0xf0) == com_in) {
int reg=com&15;
com&=0xf0;
storage=new Storage(Storage.RegisterPointer,reg, mem.getByte(this.adress));
this.adress=this.adress+1;
}
else if ((com & 0xf0) == com_out) {
int reg=com&15;
com&=0xf0;
storage=new Storage(Storage.PointerRegister,mem.getByte(this.adress),reg);
this.adress=this.adress+1;
}
}
public int getAdress() {
return adress;
}
public void setAdress(int adress) {
this.adress = adress;
}
public Storage getStorage() {
return storage;
}
public int getCom() {
return com;
}
public void run() {
int u;
int v;
Memory mem=Memory.instance();
mem.setPC(this.adress);
switch (com) {
case com_nop: // 00 00000000
break;
case com_hlt: // 01 00000001
CpuState.instance().halt();
break;
case com_clc: // 02 00000010
mem.setCFlag(false);
break;
case com_setc: // 04 00000100
mem.setCFlag(true);
break;
case com_reti: // 3f
mem.setEnableInterrupt(true);
mem.setPC(mem.popWord());
break;
case com_ld: // 08+t 00001ttt [rrrrRRRR | 0000rrrr] [n | nn]
storage.set(storage.get());
break;
case com_add: // 10+t 000100tt [rrrrRRRR | 0000rrrr] [n | nn]
u=storage.getDestinationValue();
v=u+storage.get();
storage.set(v);
storage.checkAndSetFlags(v);
break;
case com_adc: // 14+t 000101tt [rrrrRRRR | 0000rrrr] [n | nn]
u=storage.getDestinationValue();
v=storage.get();
if (Memory.instance().hasCFlag()) v++;
v+=u;
storage.set(v);
storage.checkAndSetFlags(v);
break;
case com_sub: // 18+t 000110tt [rrrrRRRR | 0000rrrr] [n | nn]
u=storage.getDestinationValue();
v=u-storage.get();
storage.set(v);
// System.out.println(v);
storage.checkAndSetFlags(v);
break;
case com_sbc: // 1C+t 000111tt [rrrrRRRR | 0000rrrr] [n | nn]
u=storage.getDestinationValue();
v=u-storage.get();
if (Memory.instance().hasCFlag()) storage.dec(v);
storage.set(v);
storage.checkAndSetFlags(v);
break;
case com_mul: // 20+t 001000tt [rrrrRRRR | 0000rrrr] [n | nn]
u=storage.getDestinationValue();
v=u*storage.get();
storage.set(v);
storage.checkAndSetFlags(v);
break;
case com_div: // 24+t 001001tt [rrrrRRRR | 0000rrrr] [n | nn]
u=storage.getDestinationValue();
v=storage.get();
if (v!=0) {
u/=v;
storage.set(u);
storage.checkAndSetFlags(u);
}
break;
case com_and: // 28+t 001010tt [rrrrRRRR | 0000rrrr] [n | nn]
u=storage.getDestinationValue();
v=u & storage.get();
storage.set(v);
storage.checkAndSetFlags(v);
break;
case com_or: // 2C+t 001011tt [rrrrRRRR | 0000rrrr] [n | nn]
u=storage.getDestinationValue();
v=u | storage.get();
storage.set(v);
storage.checkAndSetFlags(v);
break;
case com_xor: // 30+t 001100tt [rrrrRRRR | 0000rrrr] [n | nn]
u=storage.getDestinationValue();
v=u ^ storage.get();
storage.set(v);
storage.checkAndSetFlags(v);
break;
case com_cmp: // 34+t 001101tt [rrrrRRRR | 0000rrrr] [n | nn]
u=storage.getDestinationValue();
v=u-storage.get();
storage.checkAndSetFlags(v);
break;
case com_mod: // 38+t 001100tt [rrrrRRRR | 0000rrrr] [n | nn]
u=storage.getDestinationValue();
v=u % storage.get();
storage.set(v);
storage.checkAndSetFlags(v);
break;
case com_jp: // 40+f 01000fff nn
if (storage.tryFlags()) {
mem.setPC(storage.get());
}
break;
case com_call:// 48+f 01001fff nn
if (storage.tryFlags()) {
mem.pushWord(mem.getPC());
mem.setPC(storage.get());
}
break;
case com_jr: // 50+f 01010fff n
if (storage.tryFlags()) {
int n=storage.get();
if (n>127) n-=256;
mem.setPC(mem.getPC()+n);
}
break;
case com_ret: // 58+f 01011fff
if (storage.tryFlags()) {
mem.setPC(mem.popWord());
}
break;
case com_push:// 60+r 0110rrrr
if (storage.isByte()) {
mem.pushByte(storage.get());
}
else {
mem.pushWord(storage.get());
}
break;
case com_pop: // 70+r 0111rrrr
if (storage.isByte()) {
storage.set(mem.popByte());
}
else {
storage.set(mem.popWord());
}
break;
case com_shl: // 80+r 1000rrrr
u=storage.get();
storage.set(u<<1);
mem.setFlag(Memory.flagC, (u &0x80)>0);
break;
case com_shr: // 90+r 1001rrrr
u=storage.get();
storage.set(u>>1);
mem.setFlag(Memory.flagC, (u & 1)>0);
break;
case com_rhl: // A0+r 1010rrrr
v=storage.get()<<1;
if (mem.hasCFlag()) {
v+=1;
}
storage.set(v);
storage.checkAndSetFlags(v);
break;
case com_rhr: // B0+r 1011rrrr
u=storage.get();
v=u>>1;
if (mem.hasCFlag()) {
v+=128;
}
storage.set(v);
mem.setFlag(Memory.flagC, (u % 1)>0);
storage.checkAndSetFlags(v);
break;
case com_inc: // C0+r 1100rrrr
v=storage.get()+1;
storage.set(v);
storage.checkAndSetFlags(v);
break;
case com_dec: // D0+r 1101rrrr
v=storage.dec(storage.get());
storage.set(v);
storage.checkAndSetFlags(v);
break;
case com_in: // E0+r 1110rrrr n
u=storage.getSource();
switch (u) {
case 0: // keyboard
v=Keyboard.instance().getKey();
storage.set(v);
break;
case 1: // random
v=(int)(Math.random()*256);
storage.set(v);
break;
case 2: // get loudness
v=Sound.getLoudness();
storage.set(v);
break;
case 3: // get length
v=Sound.getLength();
storage.set(v);
break;
case 4: // get lengthUnit
v=Sound.getLengthUnit();
storage.set(v);
break;
case 5: // is finished?
v=Sound.isFinished()?1:0;
storage.set(v);
break;
case 6: // get tempo?
v=Sound.getBpm();
storage.set(v);
break;
default:
break;
}
case com_out: // F0+r 1111rrrr n
u=storage.get();
v=storage.getDestination();
switch (v) {
case 0:
if (u==0x0ff) {
Keyboard.instance().clear();
}
break;
case 2: // set loudness
Sound.setLoudness(u);
break;
case 3: // set length
Sound.setLength(u);
break;
case 4: // set lengthUnit
Sound.setLengthUnit(u);
break;
case 5: // >0: append tone and play; ==0: clear queue
if (u==0)
Sound.clearQueue();
else
Sound.play(u);
break;
case 6: // set (1/4)Beats Per Minute
Sound.setBpm(u);
break;
default:
break;
}
break;
default:
}
}
public String toString() {
String e="";
e+="com = "+Assembler.int2hex(this.com,2)+" ";
if (storage!=null) e+=storage.toString();
return e;
}
public static void main(String[] args) {
Memory mem=Memory.instance();
mem.setByte(0, Command.com_ld+Storage.RegisterConstant);
mem.setByte(1, Memory.regBC);
mem.setWord(2, 0x7801);
mem.setByte(4, Command.com_ld+Storage.RegisterPointer);
mem.setByte(5, Memory.regA*16+Memory.regBC);
mem.setByte(6, Command.com_inc+Memory.regA);
mem.setByte(7, Command.com_ld+Storage.PointerRegister);
mem.setByte(8, Memory.regBC*16+Memory.regA);
mem.setByte(9, Command.com_jp);
mem.setWord(10, 0x0004);
System.out.println(mem.regsString());
for (int i=0; i<10; i++) {
Command c=new Command();
c.run();
System.out.println(c);
System.out.println(mem.regsString());
System.out.println("(7801)="+Assembler.int2hex(mem.getByte(0x7801), 2));
}
}
}