OpenCores
URL https://opencores.org/ocsvn/z3/z3/trunk

Subversion Repositories z3

[/] [z3/] [trunk/] [z3.vl] - Rev 2

Compare with Previous | Blame | View Log

module boss(clk, adcDout, reset, data, waddress, we, pe, romCS, ramCS, led0, led1, led2, lcdCS, lcdRS, lcdReset, nadcCS, a17, a18);

input clk;
input adcDout;
input reset;

inout [7:0] data;

output [16:0] waddress;
output we;
output pe;
output romCS;
output ramCS;
output led0;
output led1;
output led2;
output lcdCS;
output lcdRS;
output lcdReset;
output nadcCS;
output a17;
output a18;

reg [16:0] address;
reg [7:0] dataOut;
reg printEnable;
reg writeEnable;
reg rlcdRS;
reg rlcdReset;
reg adcCS;
reg a17;
reg a18;

wire [16:0] waddress;
wire we;
wire pe;
wire romCS;
wire ramCS;
wire led0;
wire led1;
wire led2;
wire lcdCS;
wire lcdRS;
wire lcdReset;
wire nadcCS;


//`define HARDWARE_PRINT
//`define REAL_HARDWARE

`define CALLBACK_BASE           'h1E58B
`define INIT_CALLBACK           'h0
`define PRINT_CALLBACK          'h1
`define PRINTCHAR_CALLBACK      'h2
`define PRINTNUM_CALLBACK       'h3
`define READ_CALLBACK           'h4
`define STATUS_CALLBACK         'h5
`define QUIT_CALLBACK           'h6
`define EXCEPTION_CALLBACK      'h7

`define OPER_LARGE 2'b00
`define OPER_SMALL 2'b01
`define OPER_VARI  2'b10
`define OPER_OMIT  2'b11

`define STATE_RESET             0
`define STATE_FETCH_OP          1
`define STATE_READ_TYPES        2
`define STATE_READ_OPERS        3
`define STATE_READ_INDIRECT     4
`define STATE_READ_STORE        5
`define STATE_READ_BRANCH       6
`define STATE_DO_OP                     7
`define STATE_READ_FUNCTION     8
`define STATE_CALL_FUNCTION     9
`define STATE_RET_FUNCTION      10
`define STATE_STORE_REGISTER 11
`define STATE_PRINT                     12
`define STATE_DIVIDE            13
`define STATE_HALT                      14
`define STATE_PRINT_CHAR        15

`define OP_0    2'b00
`define OP_1    2'b01
`define OP_2    2'b10
`define OP_VAR  2'b11

`define OP0_RTRUE       'h0
`define OP0_RFALSE      'h1
`define OP0_PRINT       'h2
`define OP0_PRINTRET 'h3
`define OP0_NOP         'h4
`define OP0_SAVE        'h5
`define OP0_RESTORE     'h6
`define OP0_RESTART     'h7
`define OP0_RETPOP      'h8
`define OP0_POP         'h9
`define OP0_QUIT        'hA
`define OP0_NEWLINE     'hB
`define OP0_SHOWSTATUS  'hC
`define OP0_VERIFY      'hD
`define OP0_DYNAMIC     'hF

`define OP1_JZ          'h0
`define OP1_GETSIBLING 'h1
`define OP1_GETCHILD 'h2
`define OP1_GETPARENT 'h3
`define OP1_GETPROPLEN 'h4
`define OP1_INC         'h5
`define OP1_DEC         'h6
`define OP1_PRINTADDR 'h7
`define OP1_SWITCHBANK 'h8
`define OP1_REMOVEOBJ 'h9
`define OP1_PRINTOBJ 'hA
`define OP1_RET         'hB
`define OP1_JUMP        'hC
`define OP1_PRINTPADDR 'hD
`define OP1_LOAD 'hE
`define OP1_NOT 'hF

`define OP2_JE          'h1
`define OP2_JL          'h2
`define OP2_JG          'h3
`define OP2_DEC_CHK     'h4
`define OP2_INC_CHK     'h5
`define OP2_JIN         'h6
`define OP2_TEST        'h7
`define OP2_OR          'h8
`define OP2_AND         'h9
`define OP2_TESTATTR 'hA
`define OP2_SETATTR 'hB
`define OP2_CLEARATTR 'hC
`define OP2_STORE       'hD
`define OP2_INSERTOBJ 'hE
`define OP2_LOADW       'hF
`define OP2_LOADB       'h10
`define OP2_GETPROP     'h11
`define OP2_GETPROPADDR 'h12
`define OP2_GETNEXTPROP 'h13
`define OP2_ADD         'h14
`define OP2_SUB         'h15
`define OP2_MUL         'h16
`define OP2_DIV         'h17
`define OP2_MOD         'h18
`define OP2_WRITEREG 'h1E

`define OPVAR_CALL   'h0
`define OPVAR_STOREW 'h1
`define OPVAR_STOREB 'h2
`define OPVAR_PUTPROP 'h3
`define OPVAR_SREAD  'h4
`define OPVAR_PRINTCHAR 'h5
`define OPVAR_PRINTNUM 'h6
`define OPVAR_RANDOM 'h7
`define OPVAR_PUSH 'h8
`define OPVAR_PULL 'h9
`define OPVAR_GETTOUCH 'h1E
`define OPVAR_BLIT1     'h1F

`define PRINTEFFECT_FETCH               0
`define PRINTEFFECT_FETCHAFTER  1
`define PRINTEFFECT_RET1                2
`define PRINTEFFECT_ABBREVRET   3

reg forceStaticRead;
reg forceDynamicRead;

reg [3:0] state;
reg [3:0] phase;

reg [16:0] pc;
reg [16:0] curPC;
reg [15:0] globalsAddress;
reg [15:0] objectTable;

reg readHigh;

reg [4:0] op;
reg [1:0] operNum;
reg [1:0] operTypes [4:0];
reg [15:0] operand [3:0];
reg [2:0] operandIdx;
reg [13:0] branch;
reg [7:0] store;
reg negate;

reg delayedBranch;
reg divideAddOne;

reg [15:0] returnValue;

reg [6:0] opsToRead;
reg [6:0] currentLocal; 
reg [16:0] csStack;
reg [15:0] stackAddress;

reg [16:0] temp;
reg [15:0] random;

reg [1:0] alphabet;
reg [1:0] long;
reg nextLoadIsDynamic;
reg lastWriteWasDraw;

reg adcClk;
reg adcDin;

reg [7:0] cachedReg;
reg [15:0] cachedValue;

// xp<=adcConfig[0]?0:'bZ;
// yp<=adcConfig[1]?1:'bZ;
// xm<=adcConfig[2]?1:'bZ;
// ym<=adcConfig[3]?0:'bZ;
// XP dataOut[6]
// XM lcsRS
// YP dataOut[7]
// YM lcdWR

initial
begin
        state=`STATE_RESET;
        forceDynamicRead=0;
        forceStaticRead=0;
        writeEnable=0;
        printEnable=0;
        phase=0;
        readHigh=0;
        nextLoadIsDynamic=0;
        adcCS=0;
        a17=0;
        a18=0;
        cachedReg=0;
        cachedValue=0;
        lastWriteWasDraw=0;
end

assign waddress[16:2] = address[16:2];
assign waddress[0] = adcCS?adcClk:address[0];
assign waddress[1] = adcCS?adcDin:address[1];
assign data[5:0] = (writeEnable || printEnable)?dataOut[5:0]:6'bZ;
assign data[6] = (writeEnable || printEnable)?dataOut[6]:((adcCS && operand[0][0])?0:'bZ);
assign data[7] = (writeEnable || printEnable)?dataOut[7]:((adcCS && operand[0][1])?1:'bZ);
assign romCS = !(!adcCS && !printEnable && !writeEnable && !forceDynamicRead && (forceStaticRead || address[16]==1));
assign ramCS = !(!adcCS && !printEnable && (writeEnable || forceDynamicRead || (!forceStaticRead && address[16]==0)));
assign pe = adcCS?(operand[0][3]?0:'bZ):(!printEnable || !clk);
assign we = !writeEnable;
assign led0 = !address[12];
assign led1 = !address[13];
assign led2 = !address[14];
assign lcdCS = !printEnable || !clk;
assign lcdRS = adcCS?(operand[0][2]?1:'bZ):rlcdRS;
assign lcdReset = rlcdReset;
assign nadcCS = !adcCS;

task StoreB;
        begin
                if (phase==0) begin
                        cachedReg<=15; nextLoadIsDynamic<=0; address<=operand[0]+operand[1]; writeEnable<=1; dataOut<=operand[2][7:0]; phase<=phase+1;
                end else begin
                        address<=pc; writeEnable<=0; state<=`STATE_FETCH_OP;
                end
        end
endtask

task StoreW;
        begin
                case (phase)
                        0: begin cachedReg<=15; nextLoadIsDynamic<=0; address<=operand[0]+operand[1]*2; writeEnable<=1; dataOut<=operand[2][15:8]; phase<=phase+1; end
                        1: begin address<=address+1; dataOut<=operand[2][7:0]; phase<=phase+1; end
                        default: begin address<=pc; writeEnable<=0; state<=`STATE_FETCH_OP; end
                endcase
        end
endtask

task StoreRegisterAndBranch;
        input [7:0] regNum;
        input [15:0] value;
        input doBranch;
        begin
                state<=`STATE_STORE_REGISTER;
                store<=regNum;
                returnValue<=value;
                delayedBranch<=doBranch;
                phase<=0;
        end
endtask

task StoreResultAndBranch;
        input [15:0] result;
        input doBranch;
        begin
                if (store>=16) begin
                        address<=globalsAddress+2*(store-16);
                end else if (store==0) begin
                        address<=2*stackAddress;
                        stackAddress<=stackAddress+1;
                end else begin
                        address<=csStack+8+2*(store-1);
                end
                dataOut<=result[15:8];
                writeEnable<=1;
                state<=`STATE_STORE_REGISTER;
                returnValue[7:0]<=result[7:0];
                delayedBranch<=doBranch;
                phase<=1;
        end
endtask

task StoreResult;
        input [15:0] result;
        begin
                StoreResultAndBranch(result, negate); // negate means won't branch
        end
endtask

task StoreResultSlow;
        input [15:0] result;
        begin
                StoreRegisterAndBranch(store, result, negate); // negate means won't branch
        end
endtask

task ReturnFunction;
        input [15:0] value;
        begin
                returnValue<=value;
                phase<=0;
                state<=`STATE_RET_FUNCTION;
        end
endtask

task CallFunction;
        input doubleReturn;
        input noStoreOnReturn;
        begin
                negate<=doubleReturn;
                delayedBranch<=noStoreOnReturn;
                phase<=0;
                state<=`STATE_CALL_FUNCTION;
        end
endtask

task DoBranch;
        input result;
        begin
                if ((!result)==negate) begin
                        if (branch==0) begin
                                ReturnFunction(0);
                        end else if (branch==1) begin
                                ReturnFunction(1);
                        end else begin
                                pc<=$signed(pc)+$signed(branch)-2;
                                address<=$signed(pc)+$signed(branch)-2;
                                state<=`STATE_FETCH_OP;
                        end
                end else begin
                        address<=pc;
                        state<=`STATE_FETCH_OP;
                end
        end
endtask

task LoadAndStore;
        input [16:0] loadAddress;
        input            word;
        begin
                if (phase==0) begin
                        store<=data;
                        forceDynamicRead<=nextLoadIsDynamic;
                        nextLoadIsDynamic<=0;
                        address<=loadAddress;
                        temp[7:0]<=0;
                        phase<=word?phase+1:2;
                end else if (phase==1) begin
                        temp[7:0]<=data;
                        address<=address+1;
                        phase<=phase+1;
                end else begin
                        forceDynamicRead<=0;
                        StoreResultSlow((temp[7:0]<<8)|data);
                end
        end
endtask

function [16:0] GetObjectAddr;
        input [7:0] object;
        begin
                GetObjectAddr=objectTable+2*31+9*(object-1);
        end
endfunction

task TestAttr;
        begin
                if (phase==0) begin
                        address<=GetObjectAddr(operand[0])+(operand[1]/8); phase<=phase+1;
                end else begin
                        DoBranch(data[7-(operand[1]&7)]);
                end
        end
endtask

task SetAttr;
        begin
                case (phase)
                        0: begin address<=GetObjectAddr(operand[0])+(operand[1]/8); phase<=phase+1; end
                        1: begin dataOut<=data|(1<<(7-(operand[1]&7))); writeEnable<=1; phase<=phase+1; end
                        default: begin writeEnable<=0; address<=pc; state=`STATE_FETCH_OP; end
                endcase
        end
endtask

task ClearAttr;
        begin
                case (phase)
                        0: begin address<=GetObjectAddr(operand[0])+(operand[1]/8); phase<=phase+1; end
                        1: begin dataOut<=data&(~(1<<(7-(operand[1]&7)))); writeEnable<=1; phase<=phase+1; end
                        default: begin writeEnable<=0; address<=pc; state=`STATE_FETCH_OP; end
                endcase
        end
endtask

task JumpIfParent;
        begin
                if (phase==0) begin
                        address<=GetObjectAddr(operand[0])+4; phase<=phase+1;
                end else begin
                        DoBranch(operand[1]==data);
                end
        end
endtask

task GetRelative;
        input [1:0] offset;
        input branch;
        begin
                if (phase==0) begin
                        address<=GetObjectAddr(operand[0])+4+offset; phase<=phase+1;
                end else begin
                        StoreResultAndBranch(data, branch?data!=0:negate);
                end
        end
endtask

task FindProp;
        begin
                case (phase[2:0])
                        0: begin store<=data; address<=GetObjectAddr(operand[0])+7; phase<=phase+1; end
                        1: begin temp[16]<=0; temp[15:8]<=data; temp[7:0]<=0; address<=address+1; phase<=phase+1; end
                        2: begin address<=temp|data; phase<=phase+1; end
                        3: begin address<=address+2*data+1; phase<=phase+1; end
                        4: begin
                                if (data==0) begin      // end of search (get default)
                                        address<=objectTable+2*(operand[1]-1);
                                        phase<=phase+1;
                                end else if (data[4:0]==operand[1]) begin // found property
                                        address<=address+1;
                                        if (data[7:5]==0) // only 1 byte
                                                phase<=6;
                                        else
                                                phase<=5;
                                end else begin // skip over data
                                        address<=address+data[7:5]+2;
                                end
                        end
                        5: begin temp[7:0]<=data; address<=address+1; phase<=phase+1; end
                        default: begin StoreResultSlow((temp[7:0]<<8)|data); end
                endcase
        end
endtask

task SetProp;
        begin
                case (phase[2:0])
                        0: begin address<=GetObjectAddr(operand[0])+7; phase<=phase+1; end
                        1: begin temp[16]<=0; temp[15:8]<=data; temp[7:0]<=0; address<=address+1; phase<=phase+1; end
                        2: begin address<=temp|data; phase<=phase+1; end
                        3: begin address<=address+2*data+1; phase<=phase+1; end
                        4: begin
`ifndef REAL_HARDWARE
                                if (data==0) begin // end of search
                                        state<=`STATE_HALT;
                                end else
`endif
                                if (data[4:0]==operand[1]) begin // found property
                                        if (data[7:5]==0) begin // only 1 byte
                                                dataOut<=operand[2][7:0];
                                                phase<=6;
                                                address<=address+1;
                                                writeEnable<=1;
                                        end else begin
                                                dataOut<=operand[2][15:8];
                                                phase<=5;
                                                address<=address+1;
                                                writeEnable<=1;
                                        end
                                end else begin // skip over data
                                        address<=address+data[7:5]+2;
                                end
                        end
                        5: begin dataOut<=operand[2][7:0]; address<=address+1; phase<=phase+1; end
                        default: begin state<=`STATE_FETCH_OP; address<=pc; writeEnable<=0; end
                endcase
        end
endtask

task FindPropAddrLen;
        begin
                case (phase[2:0])
                        0: begin store<=data; address<=GetObjectAddr(operand[0])+7; phase<=phase+1; end
                        1: begin temp[16]<=0; temp[15:8]<=data; temp[7:0]<=0; address<=address+1; phase<=phase+1; end
                        2: begin address<=temp|data; phase<=phase+1; end
                        3: begin address<=address+2*data+1; phase<=phase+1; end
                        default: begin
                                if (data==0) begin      // end of search
                                        StoreResultSlow(0);
                                end else if (data[4:0]==operand[1]) begin // found property
                                        StoreResultSlow(address+1);
                                end else begin // skip over data
                                        address<=address+data[7:5]+2;
                                end
                   end
                endcase
        end
endtask

task FindNextProp;
        begin
                case (phase[2:0])
                        0: begin store<=data; address<=GetObjectAddr(operand[0])+7; phase<=phase+1; end
                        1: begin temp[16]<=0; temp[15:8]<=data; temp[7:0]<=0; address<=address+1; phase<=phase+1; end
                        2: begin address<=temp|data; phase<=phase+1; end
                        3: begin address<=address+2*data+1; phase<=phase+1; end
                        default: begin
                                if (operand[1]==0)
                                        StoreResultSlow(data[4:0]);
`ifndef REAL_HARDWARE
                                else if (data==0)       // end of search
                                        state<=`STATE_HALT;
`endif
                                else begin // skip over data
                                        if (data[4:0]==operand[1])
                                                operand[1]<=0;
                                        address<=address+data[7:5]+2;
                                end
                   end
                endcase
        end
endtask

task GetPropLen;
        begin
                if (phase==0) begin
                        address<=operand[0]-1; phase<=phase+1;
                end else begin
                        StoreResultSlow((operand[0]==0)?0:(data[7:5]+1));
                end
        end
endtask

task Pull;
        input return;
        begin
                case (phase)
                        0: begin
                                address<=2*(stackAddress-1);
                                forceDynamicRead<=1;
                                phase<=phase+1;
                        end
                        1: begin
                                temp[7:0]<=data;
                                stackAddress<=address>>1;
                                address<=address+1;
                                phase<=phase+1;
                        end
                        default: begin
                                forceDynamicRead<=0;
                                if (return) begin
                                        ReturnFunction((temp[7:0]<<8)|data);
                                end else begin
                                        if (operand[0]==0)
                                                stackAddress<=stackAddress-1;
                                        StoreRegisterAndBranch(operand[0], (temp[7:0]<<8)|data, negate);
                                end
                        end
                endcase

        end
endtask

task Print;
        input [16:0] addr;
        input [1:0] effect;
        begin
                temp<=addr;
                state<=`STATE_PRINT;
                returnValue[1:0]<=effect;
                delayedBranch<=0;
                phase<=0;
        end
endtask

task PrintObj;
        begin
                case (phase[1:0])
                        0: begin address<=GetObjectAddr(operand[0])+7; phase<=phase+1; end
                        1: begin store<=data; address<=address+1; phase<=phase+1; end
                        default: Print((store<<8)+data+1, `PRINTEFFECT_FETCH);
                endcase
        end
endtask

task RemoveObject;
        begin
                case (phase[3:0])
                        0: begin address<=GetObjectAddr(operand[0])+4; /*obj.parent*/ phase<=phase+1; end
                        1: begin
                                if (data==0) begin
                                        phase<=(operand[1]!=0)?6:9;
                                end else begin
                                        phase<=phase+1;
                                end
                                temp[15:8]<=data;
                                writeEnable<=1;
                                dataOut<=operand[1];
                        end
                        2: begin writeEnable<=0; address<=address+1; /*obj.sibling*/ phase<=phase+1; end
                        3: begin temp[7:0]<=data; writeEnable<=1; dataOut<=0; phase<=phase+1; end
                        4: begin writeEnable<=0; address<=GetObjectAddr(temp[15:8])+6; /*parent.child*/ phase<=phase+1; end
                        5: begin
                                if (data==operand[0]) begin // found object
                                        dataOut<=temp[7:0];
                                        writeEnable<=1;
                                        phase<=(operand[1]!=0)?phase+1:9;
                                end else begin
                                        address<=GetObjectAddr(data)+5; /*follow sibling*/
                                end
                        end

                        6: begin address<=GetObjectAddr(operand[1])+6; writeEnable<=0; phase<=phase+1; end
                        7: begin temp[7:0]<=data; writeEnable<=1; dataOut<=operand[0]; phase<=phase+1; end
                        8: begin address<=GetObjectAddr(operand[0])+5; dataOut<=temp[7:0]; phase<=phase+1; end
                        default: begin
                                writeEnable<=0;
                                state<=`STATE_FETCH_OP;
                                address<=pc;
                        end
                endcase
        end
endtask

task Random;
        begin
                case (phase)
                        0: begin if ($signed(operand[0])<0) begin random<=operand[0]; state<=`STATE_FETCH_OP; end else begin random<=random^(random<<13); end phase<=phase+1; end
                        1: begin random<=random^(random>>9); phase<=phase+1; end
                        2: begin random<=random^(random<<7); phase<=phase+1; end
                        default: begin state<=`STATE_DIVIDE; delayedBranch<=1; divideAddOne<=1; operand[1]<=operand[0]; operand[0]<=random&'h7FFF; phase<=0; end
                endcase
        end
endtask

task PrintNum;
        begin
`ifdef HARDWARE_PRINT
                case (phase)
                        0: begin negate<=0; operand[1]<=1; operand[2][2:0]<=2; operand[3][3:0]<=0; phase<=phase+1; end
                        1,2,3,4: begin operand[1]<=(operand[1]<<3)+(operand[1]<<1); printEnable<=0; phase<=phase+1; end
                        5: begin
                                if (operand[0]>=operand[1]) begin
                                        operand[0]<=operand[0]-operand[1];
                                        operand[3][3:0]<=operand[3][3:0]+1;
                                        negate<=1;
                                        printEnable<=0;
                                end else begin
                                        printEnable<=negate;
                                        dataOut<=operand[3][3:0]+48;
                                        operand[3][3:0]<=0;
                                        operand[1]<=1;
                                        operand[2][2:0]<=operand[2][2:0]+1;
                                        phase<=operand[2][2:0];
                                end
                        end
                        default: begin printEnable<=0; state<=`STATE_FETCH_OP; end
                endcase
`else
                operand[0]<=`PRINTNUM_CALLBACK;
                operand[1]<=operand[0];
                operTypes[1]<=`OPER_LARGE;
                CallFunction(0, 1);
`endif
        end
endtask

task PrintChar;
        input [7:0] char;
        begin
                $display("Print char: %d\n", char);
`ifdef HARDWARE_PRINT
                printEnable<=1;
                dataOut<=char;
                state<=`STATE_PRINT_CHAR;
`else
                operand[0]<=`PRINTCHAR_CALLBACK;
                operand[1]<=char;
                operTypes[1]<=`OPER_LARGE;
                CallFunction(0, 1);
`endif
        end
endtask

task SRead;
        begin
                operand[0]<=`READ_CALLBACK;
                operand[2]<=operand[0]; // Am swapping arguments just to save space on FPGA
                operTypes[2]<=`OPER_LARGE;
                CallFunction(0, 1);
        end
endtask

task WriteReg;
        begin
                case (phase)
                        0: begin lastWriteWasDraw<=(operand[0]=='h22); if (operand[0]=='h22 && lastWriteWasDraw) begin rlcdRS<=1; phase<=4; end else begin rlcdRS<=0; phase<=phase+1; end end 
                        1: begin dataOut<=operand[0][15:8]; printEnable<=1; phase<=phase+1; end
                        2: begin dataOut<=operand[0][7:0]; if (operand[0]==0) phase<=4; else phase<=phase+1; end
                        3: begin rlcdRS<=1; printEnable<=0; phase<=phase+1; end
                        4: begin dataOut<=operand[1][15:8]; printEnable<=1; phase<=phase+1; end
                        5: begin dataOut<=operand[1][7:0]; phase<=phase+1; end
                        default: begin printEnable<=0; address<=pc; state<=`STATE_FETCH_OP; end
                endcase
        end
endtask

task Blit1;
        begin
                case (phase)
                        0: begin forceDynamicRead<=1; rlcdRS<=0; phase<=phase+1; end
                        1: begin dataOut<=0; printEnable<=1; phase<=phase+1; end
                        2: begin address<=operand[0]*2; dataOut<=34; returnValue<=0; phase<=phase+1; end
                        3: begin
                                rlcdRS<=1;
                                printEnable<=0;
                                if (operand[1]==0) begin
                                        forceDynamicRead<=0;
                                        address<=pc;
                                        state<=`STATE_FETCH_OP;
                                end
                                phase<=phase+1;
                        end
                        4: begin
                                store<=data;
                                dataOut<=data[7]?operand[3][15:8]:operand[2][15:8];
                                printEnable<=1;
                                phase<=6;
                        end
                        5: begin
                                dataOut<=store[7]?operand[3][15:8]:operand[2][15:8];
                                printEnable<=1;
                                phase<=phase+1;
                        end
                        default: begin
                                dataOut<=store[7]?operand[3][7:0]:operand[2][7:0];
                                store[7:1]=store[6:0];
                                returnValue<=returnValue+1;
                                if (returnValue[2:0]==7) begin
                                        operand[1]=operand[1]-1;
                                        phase<=3;
                                        address<=address+1;
                                end else begin
                                        phase<=5;
                                end
                        end
                endcase
        end
endtask

task GetTouch;
        begin
                case (phase)
                        0: begin
                                adcCS<=1;
                                adcClk<=0;
                                adcDin<=1;
                                operand[1]<='hffff;
                           operand[2]<=1;
                                phase<=1;
                        end
                        1: begin
                                operand[2][3:0]<=operand[2][3:0]+1;
                                if (operand[2][3:0]==0) begin                   // Max clock rate for ADC is ~ 1MHz so divide our clock by 16
                                        adcClk<=1;
                                        operand[1]<=(operand[1]<<1)+adcDout;
                                        phase<=(!operand[1][9])?3:2;
                                end
                        end
                        2: begin
                                operand[2][3:0]<=operand[2][3:0]+1;
                                if (operand[2][3:0]==0) begin                   // Max clock rate for ADC is ~ 1MHz so divide our clock by 16
                                        operand[0][8:4]<=(operand[0][8:4]>>1);
                                        adcDin<=operand[0][4];
                                        adcClk<=0;
                                        phase<=1;
                                end
                        end
                        default: begin adcCS<=0; StoreResultSlow(operand[1]&'h3FF); end
                endcase
        end
endtask

task DoOp;
        begin
                case (operNum)
                        `OP_0: begin
                                if (phase==0)
                                        $display("PC:%h Doing op0:%d Store:%h Branch:%h/%d", curPC, op, operand[0], store, branch, negate);
                                case (op[3:0])
                                        `OP0_RTRUE: ReturnFunction(1);
                                        `OP0_RFALSE: ReturnFunction(0);
                                        `OP0_PRINT: Print(pc, `PRINTEFFECT_FETCHAFTER);
                                        `OP0_PRINTRET: Print(pc, `PRINTEFFECT_RET1);
                                        `OP0_SAVE,`OP0_RESTORE: DoBranch(0);
                                        `OP0_RESTART: state<=`STATE_RESET;
                                        `OP0_RETPOP: Pull(1);
                                        `OP0_QUIT: begin operand[0]<=`QUIT_CALLBACK; CallFunction(0,1); end
                                        `OP0_NEWLINE: PrintChar(10);
                                        `OP0_SHOWSTATUS: begin operand[0]<=`STATUS_CALLBACK; CallFunction(0,1); end
                                        `OP0_VERIFY: DoBranch(1);
                                        default: state<=`STATE_HALT;
                                endcase
                        end
                        `OP_1: begin
                                if (phase==0)
                                        $display("PC:%h Doing op1:%d Operands:%h Store:%h Branch:%h/%d", curPC, op, operand[0], store, branch, negate);
                                case (op[3:0])
                                        `OP1_JZ: DoBranch(operand[0]==0);
                                        `OP1_GETSIBLING: GetRelative(1,1);
                                        `OP1_GETCHILD: GetRelative(2,1);
                                        `OP1_GETPARENT: GetRelative(0,0);
                                        `OP1_GETPROPLEN: GetPropLen();
                                        `OP1_INC: StoreResult(operand[0]+1);
                                        `OP1_DEC: StoreResult(operand[0]-1);
                                        `OP1_PRINTADDR: Print(operand[0], `PRINTEFFECT_FETCH);
                                        `OP1_SWITCHBANK: begin a17<=operand[0][0]; a18<=operand[0][1]; state<=`STATE_RESET; end
                                        `OP1_REMOVEOBJ: begin operNum<=`OP_2; op<=`OP2_INSERTOBJ; operand[1]<=0; end
                                        `OP1_PRINTOBJ: PrintObj();
                                        `OP1_RET: ReturnFunction(operand[0]);
                                        `OP1_JUMP: begin pc<=$signed(pc)+$signed(operand[0])-2; address<=$signed(pc)+$signed(operand[0])-2; state<=`STATE_FETCH_OP; end
                                        `OP1_PRINTPADDR: Print(2*operand[0], `PRINTEFFECT_FETCH); 
                                        `OP1_LOAD: StoreResult(operand[0]);
                                        `OP1_NOT: StoreResult(~operand[0]);
                                        default: state<=`STATE_HALT;
                                endcase
                        end
                        `OP_2: begin
                                if (phase==0)
                                        $display("PC:%h Doing op2:%d Operands:%h %h Store:%h Branch:%h/%d/%h", curPC, op, operand[0], operand[1], store, branch, negate, $signed(pc)+$signed(branch-2));
                                case (op)
                                        `OP2_JE: DoBranch(operand[0]==operand[1] || (operTypes[2]!=`OPER_OMIT && operand[0]==operand[2]) || (operTypes[3]!=`OPER_OMIT && operand[0]==operand[3]));
                                        `OP2_JL: DoBranch($signed(operand[0])<$signed(operand[1]));
                                        `OP2_JG: DoBranch($signed(operand[0])>$signed(operand[1]));
                                        `OP2_INC_CHK: StoreResultAndBranch(operand[0]+1, $signed(operand[0])+1>$signed(operand[1]));
                                        `OP2_DEC_CHK: StoreResultAndBranch(operand[0]-1, $signed(operand[0])-1<$signed(operand[1]));
                                        `OP2_JIN: JumpIfParent();
                                        `OP2_TEST: DoBranch((operand[0]&operand[1])==operand[1]);
                                        `OP2_OR: StoreResult(operand[0]|operand[1]);
                                        `OP2_AND: StoreResult(operand[0]&operand[1]);
                                        `OP2_TESTATTR: TestAttr();
                                        `OP2_SETATTR: SetAttr();
                                        `OP2_CLEARATTR: ClearAttr();
                                        `OP2_STORE: begin if (operand[0]==0) stackAddress<=stackAddress-1; StoreRegisterAndBranch(operand[0], operand[1], negate); end
                                        `OP2_INSERTOBJ: RemoveObject();
                                        `OP2_LOADW: LoadAndStore(operand[0]+2*operand[1], 1);
                                        `OP2_LOADB: LoadAndStore(operand[0]+operand[1], 0);
                                        `OP2_GETPROP: FindProp();
                                        `OP2_GETPROPADDR: FindPropAddrLen();
                                        `OP2_GETNEXTPROP: FindNextProp();
                                        `OP2_ADD: StoreResult($signed(operand[0])+$signed(operand[1]));
                                        `OP2_SUB: StoreResult($signed(operand[0])-$signed(operand[1]));
                                        `OP2_MUL: StoreResult($signed(operand[0])*$signed(operand[1]));
                                        `OP2_DIV: begin store<=data; state=`STATE_DIVIDE; delayedBranch<=0; divideAddOne<=0; end
                                        `OP2_MOD: begin store<=data; state=`STATE_DIVIDE; delayedBranch<=1; divideAddOne<=0; end
                                        `OP2_WRITEREG: WriteReg();
                                        default: state<=`STATE_HALT;
                                endcase
                        end
                        default: begin // 'OP_VAR
                                if (phase==0) begin
                                        if (operTypes[0]==`OPER_OMIT)
                                                $display("PC:%h Doing opvar:%d Operands: Store:%h Branch:%h/%d/%h", curPC, op, store, branch, negate, $signed(pc)+$signed(branch-2));
                                        else if (operTypes[1]==`OPER_OMIT)
                                                $display("PC:%h Doing opvar:%d Operands:%h Store:%h Branch:%h/%d/%h", curPC, op, operand[0], store, branch, negate, $signed(pc)+$signed(branch-2));
                                        else if (operTypes[2]==`OPER_OMIT)
                                                $display("PC:%h Doing opvar:%d Operands:%h %h Store:%h Branch:%h/%d/%h", curPC, op, operand[0], operand[1], store, branch, negate, $signed(pc)+$signed(branch-2));
                                        else if (operTypes[3]==`OPER_OMIT)
                                                $display("PC:%h Doing opvar:%d Operands:%h %h %h Store:%h Branch:%h/%d/%h", curPC, op, operand[0], operand[1], operand[2], store, branch, negate, $signed(pc)+$signed(branch-2));
                                        else
                                                $display("PC:%h Doing opvar:%d Operands:%h %h %h %h Store:%h Branch:%h/%d/%h", curPC, op, operand[0], operand[1], operand[2], operand[3], store, branch, negate, $signed(pc)+$signed(branch-2));
                                end
                                case (op)
                                        `OPVAR_CALL: if (operand[0]==0) StoreResultSlow(0); else CallFunction(0, 0);
                                        `OPVAR_STOREW: StoreW();
                                        `OPVAR_STOREB: StoreB();
                                        `OPVAR_PUTPROP: SetProp();
                                        `OPVAR_SREAD: SRead();
                                        `OPVAR_PRINTCHAR: PrintChar(operand[0]);
                                        `OPVAR_PRINTNUM: PrintNum();
                                        `OPVAR_RANDOM: Random();
                                        `OPVAR_PUSH: StoreRegisterAndBranch(0, operand[0], negate);
                                        `OPVAR_PULL: Pull(0);
                                        `OPVAR_GETTOUCH: GetTouch();
                                        `OPVAR_BLIT1: Blit1();
                                        default: state<=`STATE_HALT;
                                endcase
                        end
                endcase
        end
endtask
                        
`ifdef HARDWARE_PRINT
task DoPrint;
        input [4:0] char;
        begin
                if (delayedBranch) begin
                        store[4:0]<=char;
                        operand[1]<=phase+1;
                        delayedBranch<=0;
                        phase<=6;
                end else if (long==1) begin
                        operand[3][4:0]=char;
                        long<=long+1;
                end else if (long==2) begin
                        printEnable<=1;
                        dataOut<=(operand[3][4:0]<<5)|char;
                        long<=0;
                end else begin
                        phase<=phase+1;
                        if (char==0) begin
                                printEnable<=1;
                                dataOut<=32;
                        end else if (char==4 || char==5) begin
                                printEnable<=0;
                                alphabet=char-3;
                        end else if (char>=6) begin
                                printEnable<=!(alphabet==2 && char==6);
                                if (alphabet==2) begin
                                        case (char)
                                                6: long<=1;
                                                7: dataOut<=10;
                                                8,9,10,11,12,13,14,15,16,17: dataOut<=char-8+48;
                                                18: dataOut<=46;
                                                19: dataOut<=44;
                                                20: dataOut<=33;
                                                21: dataOut<=63;
                                                22: dataOut<=95;
                                                23: dataOut<=35;
                                                24: dataOut<=39;
                                                25: dataOut<=34;
                                                26: dataOut<=47;
                                                27: dataOut<=92;
                                                28: dataOut<=45;
                                                29: dataOut<=58;
                                                30: dataOut<=40;
                                                31: dataOut<=41;
                                        endcase
                                end else begin
                                        dataOut<=char-6+((alphabet==0)?97:65);
                                end
                                alphabet<=0;
                        end else begin
                                printEnable<=0;
                                store[7:5]<=(char-1);
                                delayedBranch<=1;
                        end
                end
        end
endtask
`endif

task FinishReadingOps;
begin
        case (operNum)
                `OP_1: begin
                        case (op[3:0])
                                `OP1_INC, `OP1_DEC, `OP1_LOAD: state<=`STATE_READ_INDIRECT;
                                `OP1_GETSIBLING,`OP1_GETCHILD,`OP1_GETPARENT,`OP1_GETPROPLEN,`OP1_NOT: state<=`STATE_READ_STORE;
                                `OP1_JZ: state<=`STATE_READ_BRANCH;
                                default: state<=`STATE_DO_OP;
                        endcase
                        pc<=pc+1;
                end
                `OP_2: begin
                        case (op[4:0])
                                `OP2_INC_CHK,`OP2_DEC_CHK: begin pc<=pc+1; state<=`STATE_READ_INDIRECT; end
                                `OP2_OR,`OP2_AND,`OP2_ADD,`OP2_SUB,`OP2_MUL: begin pc<=pc+1; state<=`STATE_READ_STORE; end
                                `OP2_LOADW,`OP2_LOADB,`OP2_GETPROP ,`OP2_GETPROPADDR,`OP2_GETNEXTPROP,`OP2_DIV,`OP2_MOD: begin pc<=pc+2; state<=`STATE_DO_OP; end
                                `OP2_JE,`OP2_JL,`OP2_JG,`OP2_JIN,`OP2_TEST,`OP2_TESTATTR: begin pc<=pc+1; state<=`STATE_READ_BRANCH; end
                                default: begin pc<=pc+1; state<=`STATE_DO_OP; end
                        endcase
                end
                default: begin // `OP_VAR
                        pc<=pc+1;
                        case (op[4:0])
                                `OPVAR_CALL,`OPVAR_RANDOM,`OPVAR_GETTOUCH: state<=`STATE_READ_STORE;
                                default: state<=`STATE_DO_OP;
                        endcase
                end
        endcase
end
endtask

always @ (posedge clk)
begin
        case(state)
                `STATE_RESET: begin
                        case (phase)
                                0: begin printEnable<=0; random<=1; forceStaticRead<=1; address<='h6; phase<=phase+1; end
                                1: begin address<='h7; phase<=phase+1; pc[15:8]<=data; pc[16]<=0; end
                                2: begin address<='hA; phase<=phase+1; pc[7:0]<=data; end
                                3: begin address<='hB; phase<=phase+1; objectTable[15:8]<=data; end
                                4: begin address<='hC; phase<=phase+1; objectTable[7:0]<=data; end
                                5: begin address<='hD; phase<=phase+1; globalsAddress[15:8]<=data; end
                                6: begin address<=0; phase<=phase+1; globalsAddress[7:0]<=data; end
                                7: begin dataOut<=data; writeEnable<=1; phase<=8; end
                                8: begin writeEnable<=0; address<=address+1; if (address[15:0]=='hffff) phase<=9; else phase<=7; end
                                9: begin writeEnable<=1; dataOut<=0; address<=address+1; if (address[15:0]=='hffff) begin writeEnable<=0; phase<=10; end end
                                10: begin rlcdReset<=address[10]; rlcdRS<=1; printEnable<=0; address<=address+1; if (address[10:0]=='h7ff) phase<=11; end
                                default: begin
                                        cachedReg<=15;
                                        address<=pc;
                                        forceStaticRead<=0;
                                        stackAddress<=64*1024/2;
                                        csStack<=65*1024;
                                        operand[0]<=`INIT_CALLBACK;
                                        operTypes[1]<=`OPER_OMIT;
                                        CallFunction(0, 1);
                                end
                        endcase
                end
                `STATE_CALL_FUNCTION: begin
                        case (phase)
                                0: begin $display("Call function %h", operand[0]*2); address<=csStack; writeEnable<=1; dataOut<=(delayedBranch<<2)|(negate<<1)|pc[16]; phase<=phase+1; end
                                1: begin address<=address+1; dataOut<=pc[15:8]; phase<=phase+1; end
                                2: begin address<=address+1; dataOut<=pc[7:0]; phase<=4; end
                                3: begin end // pointless phase but for some reason saves gates
                                4: begin address<=address+1; dataOut<=stackAddress[15:8]; phase<=phase+1; end
                                5: begin address<=address+1; dataOut<=stackAddress[7:0]; phase<=phase+1; end
                                6: begin address<=address+1; dataOut<=store; phase<=(operand[0][15:3]==0)?phase+1:10; end
                                7: begin address<=`CALLBACK_BASE+5*(operand[0]&7); writeEnable<=0; phase<=phase+1; end
                                8: begin address<=address+1; operand[0][15:8]<=data; phase<=phase+1; end
                                9: begin operand[0][7:0]<=data; phase<=phase+1; end
                                default: begin
                                        cachedReg<=15;
                                        csStack<=csStack+38;
                                        address<=2*operand[0];
                                        state<=`STATE_READ_FUNCTION;
                                        writeEnable<=0;
                                        phase<=0;
                                end
                        endcase
                end
                `STATE_RET_FUNCTION: begin
                        case (phase)
                                0: begin csStack<=csStack-38; address<=csStack-38; forceDynamicRead<=1; phase<=phase+1; end
                                1: begin pc[16]<=data[0]; negate<=data[1]; delayedBranch<=data[2]; address<=address+1; phase<=phase+1; end
                                2: begin pc[15:8]<=data; address<=address+1; phase<=phase+1; end
                                3: begin pc[7:0]<=data; address<=address+1; phase<=phase+1; end
                                4: begin stackAddress[15:8]<=data; address<=address+1; phase<=phase+1; end
                                5: begin stackAddress[7:0]<=data; address<=address+1; phase<=phase+1; end
                                default: begin
                                        forceDynamicRead<=0;
                                        cachedReg<=15;
                                        if (negate) begin
                                                phase<=0;
                                        end else if (delayedBranch) begin
                                                state<=`STATE_FETCH_OP;
                                                address<=pc;
                                        end else begin
                                                StoreRegisterAndBranch(data, returnValue, negate);
                                        end
                                end
                        endcase
                end
                `STATE_READ_FUNCTION: begin
                        case (phase)
                                0: begin
                                        if (data==0) begin
                                                state<=`STATE_FETCH_OP;
                                        end else begin
                                                opsToRead<=4*data-1;
                                                phase<=phase+1;
                                        end
                                        currentLocal<=0;
                                        pc<=address+1;
                                        address<=address+1;
                                end
                                default: begin
                                        if (opsToRead&1) begin
                                                if (currentLocal<6 && operTypes[(currentLocal>>1)+1]!=`OPER_OMIT) begin
                                                        dataOut<=currentLocal[0]?operand[(currentLocal>>1)+1][7:0]:operand[(currentLocal>>1)+1][15:8];
                                                end else begin
                                                        dataOut<=data;
                                                end
                                                address<=csStack+8+currentLocal;
                                                writeEnable<=1;
                                                currentLocal<=currentLocal+1;
                                        end else begin
                                                pc<=pc+1;
                                                address<=pc+1;
                                                writeEnable<=0;
                                        end
                                        if (opsToRead==0) begin
                                                state<=`STATE_FETCH_OP;                                         
                                        end
                                        opsToRead<=opsToRead-1;
                                end
                        endcase
                end
                `STATE_FETCH_OP: begin
                        phase<=0;
                        operTypes[2]<=`OPER_OMIT;
                        operTypes[3]<=`OPER_OMIT;
                        operTypes[4]<=`OPER_OMIT;
                        curPC<=pc;
                        $display("Fetching op at %h", pc);
                        if (!reset) begin
                                state<=`STATE_RESET;
                                a17<=0;
                                a18<=0;
                        end else begin
                                case (data[7:6])
                                        2'b10: begin
                                                // short form
                                                op[4:0]<=data[3:0];
                                                operTypes[0]<=data[5:4];
                                                operTypes[1]<=`OPER_OMIT;
                                                if (data[5:4]==2'b11) begin
                                                        operNum[1:0]<=`OP_0;
                                                        case (data[3:0])
                                                                `OP0_POP: begin cachedReg<=15; stackAddress<=stackAddress-1; end
                                                                `OP0_NOP: begin /*nop*/ end
                                                                `OP0_DYNAMIC: nextLoadIsDynamic<=1;
                                                                `OP0_SAVE,`OP0_RESTORE,`OP0_VERIFY: state<=`STATE_READ_BRANCH;
                                                                default: state<=`STATE_DO_OP;
                                                        endcase
                                                end else begin
                                                        operNum[1:0]<=`OP_1;
                                                        state<=`STATE_READ_OPERS;
                                                end
                                        end
                                        2'b11: begin
                                                // variable form
                                                op[4:0]<=data[4:0];
                                                operNum[1:0]<=(data[5]?`OP_VAR:`OP_2);
                                                state<=`STATE_READ_TYPES;
                                        end
                                        default: begin
                                                // long form
                                                op[4:0]<=data[4:0];
                                                operNum[1:0]<=`OP_2;
                                                operTypes[0]<=(data[6] ? `OPER_VARI : `OPER_SMALL);
                                                operTypes[1]<=(data[5] ? `OPER_VARI : `OPER_SMALL);
                                                state<=`STATE_READ_OPERS;
                                        end
                                endcase
                        end
                        operandIdx<=0;
                        pc<=pc+1;
                        address<=pc+1;
                end
                `STATE_READ_TYPES: begin
                        operTypes[0]<=data[7:6];
                        operTypes[1]<=data[5:4];
                        operTypes[2]<=data[3:2];
                        operTypes[3]<=data[1:0];
                        address<=pc+1;
                        if (data[7:6]==`OPER_OMIT)
                                FinishReadingOps();
                        else begin
                                state<=`STATE_READ_OPERS;
                                pc<=pc+1;
                        end
                end
                `STATE_READ_OPERS: begin
                        case (operTypes[operandIdx])
                                `OPER_SMALL: begin
                                        operand[operandIdx]<=data[7:0];
                                        address<=pc+1;
                                        operandIdx<=operandIdx+1;
                                        if (operTypes[operandIdx+1]==`OPER_OMIT)
                                                FinishReadingOps();
                                        else
                                                pc<=pc+1;
                                end
                                `OPER_LARGE: begin
                                        address<=pc+1;
                                        if (!readHigh) begin
                                                operand[operandIdx][15:8]<=data[7:0];
                                                readHigh<=1;
                                                pc<=pc+1;
                                        end else begin
                                                operand[operandIdx][7:0]<=data[7:0];
                                                operandIdx<=operandIdx+1;
                                                readHigh<=0;
                                                if (operTypes[operandIdx+1]==`OPER_OMIT)
                                                        FinishReadingOps();
                                                else
                                                        pc<=pc+1;
                                        end
                                end
                                default: begin // OPER_VARI
                                        case (phase)
                                                0: begin
                                                        if (data==0) begin
                                                                stackAddress<=stackAddress-1;
                                                        end
                                                        if (cachedReg!=15 && data==cachedReg) begin
                                                                operand[operandIdx]<=cachedValue;
                                                                address<=pc+1;
                                                                operandIdx<=operandIdx+1;
                                                                if (operTypes[operandIdx+1]==`OPER_OMIT)
                                                                        FinishReadingOps();
                                                                else
                                                                        pc<=pc+1;
                                                                if (cachedReg==0)
                                                                        cachedReg<=15;
                                                        end else begin
                                                                if (data>=16) begin
                                                                        address<=globalsAddress+2*(data-16);
                                                                end else if (data==0) begin
                                                                        address<=2*(stackAddress-1);
                                                                end else begin
                                                                        address<=csStack+8+2*(data-1);
                                                                end
                                                                forceDynamicRead<=1;    
                                                                phase<=phase+1;
                                                        end
                                                end
                                                1: begin
                                                        operand[operandIdx]<=(data<<8);
                                                        address<=address+1;
                                                        phase<=phase+1;
                                                end
                                                default: begin
                                                        forceDynamicRead<=0;
                                                        operand[operandIdx]<=operand[operandIdx]|data;
                                                        address<=pc+1;
                                                        operandIdx<=operandIdx+1;
                                                        if (operTypes[operandIdx+1]==`OPER_OMIT)
                                                                FinishReadingOps();
                                                        else
                                                                pc<=pc+1;
                                                        phase<=0;
                                                end
                                        endcase
                                end
                        endcase
                end
                `STATE_READ_INDIRECT: begin
                        case (phase)
                                0: begin
                                        cachedReg<=15;
                                        store<=operand[0];
                                        if (operand[0]>=16) begin
                                                address<=globalsAddress+2*(operand[0]-16);
                                        end else if (operand[0]==0) begin
                                                if (op[4:0]!=`OP1_LOAD)
                                                        stackAddress<=stackAddress-1;
                                                address<=2*(stackAddress-1);
                                        end else begin
                                                address<=csStack+8+2*(operand[0]-1);
                                        end
                                        forceDynamicRead<=1;
                                        phase<=phase+1;
                                end
                                1: begin
                                        operand[0][15:8]<=data;
                                        address<=address+1;
                                        phase<=phase+1;
                                end
                                default: begin
                                        forceDynamicRead<=0;
                                        operand[0][7:0]<=data;
                                        if (op[4:0]==`OP1_LOAD)
                                                state<=`STATE_READ_STORE;
                                        else if (operNum==`OP_2)
                                                state<=`STATE_READ_BRANCH;
                                        else
                                                state<=`STATE_DO_OP;
                                        address<=pc;
                                        phase<=0;
                                end
                        endcase
                end
                `STATE_READ_STORE: begin
                        case (op[4:0])
                                `OP1_GETSIBLING, `OP1_GETCHILD: state<=`STATE_READ_BRANCH;
                                default: state<=`STATE_DO_OP;
                        endcase
                        store<=data;
                        pc<=pc+1;
                        address<=pc+1;
                end
                `STATE_READ_BRANCH: begin
                        if (!readHigh) begin
                                if (data[6]) begin
                                        branch<=data[5:0];
                                        negate<=!data[7];
                                        state<=`STATE_DO_OP;
                                end else begin
                                        branch[13:8]<=data[5:0];
                                        negate<=!data[7];
                                        readHigh<=1;
                                end
                        end else begin
                                branch[7:0]<=data;
                                readHigh<=0;
                                state<=`STATE_DO_OP;
                        end
                        pc<=pc+1;
                        address<=pc+1;
                end
                `STATE_DO_OP: begin
                        DoOp();
                end
                `STATE_STORE_REGISTER: begin
                        case (phase)
                                0: begin
                                        if (store>=16) begin
                                                address<=globalsAddress+2*(store-16);
                                        end else if (store==0) begin
                                                address<=2*stackAddress;
                                                stackAddress<=stackAddress+1;
                                        end else begin
                                                address<=csStack+8+2*(store-1);
                                        end
                                        dataOut<=returnValue[15:8];
                                        writeEnable<=1;
                                        phase<=phase+1;
                                end
                                1: begin
                                        cachedReg<=store;
                                        cachedValue[15:8]<=dataOut;
                                        cachedValue[7:0]<=returnValue[7:0];
                                        dataOut<=returnValue[7:0];
                                        address<=address+1;
                                        phase<=phase+1;
                                end
                                default: begin
                                        DoBranch(delayedBranch);
                                        writeEnable<=0;
                                        phase<=0;
                                end
                        endcase
                end
                `STATE_DIVIDE: begin
                        case (phase)
                                0: begin
                                        negate<=operand[0][15]^operand[1][15];
                                        readHigh<=operand[0][15];
                                        if ($signed(operand[0])<0)
                                                operand[0]<=-operand[0];
                                        else
                                                operand[0]<=operand[0];
`ifndef REAL_HARDWARE
                                        if (operand[1]==0)
                                                state=`STATE_HALT;
                                        else
`endif
                                        if ($signed(operand[1])<0)
                                                operand[1]<=-operand[1];
                                        operand[2]<=1;
                                        operand[3]<=0;
                                        phase<=phase+1;
                                end
                                1: begin
                                        if (operand[1][15] || operand[0]<=operand[1]) begin
                                                phase<=phase+1;
                                        end else begin
                                                operand[1]<=operand[1]<<1;
                                                operand[2]<=operand[2]<<1;
                                        end
                                end
                                2: begin
                                        if (operand[1]>operand[0]) begin
                                                if (operand[2]==1) begin
                                                        if (negate) begin
                                                                operand[0]<=-operand[3];
                                                        end else begin
                                                                operand[0]<=operand[3];
                                                        end
                                                        if (readHigh) begin
                                                                operand[1]<=-operand[0];
                                                        end else begin
                                                                operand[1]<=operand[0];
                                                        end
                                                        readHigh<=0;
                                                        phase<=phase+1;
                                                end else begin
                                                        operand[1]<=operand[1]>>1;
                                                        operand[2]<=operand[2]>>1;
                                                end
                                        end else begin
                                                operand[0]<=operand[0]-operand[1];
                                                operand[3]<=operand[3]+operand[2];
                                        end
                                end
                                default: begin
                                        StoreResultSlow(delayedBranch?(operand[1]+divideAddOne):operand[0]);
                                end
                        endcase
                end
                `STATE_PRINT: begin
`ifdef HARDWARE_PRINT
                        case (phase)
                                0: begin delayedValue[15:8]<=data; address<=address+1; phase<=phase+1; end
                                1: begin delayedValue[7:0] <=data; address<=address+1; phase<=phase+1; end
                                2,3,4: begin DoPrint(delayedValue[14:10]); delayedValue[14:5]<=delayedValue[9:0]; end
                                5: begin
                                        printEnable<=0;
                                        if (delayedValue[15]) begin
                                                alphabet<=0;
                                                long<=0;
                                                case (returnValue[1:0])
                                                        `PRINTEFFECT_FETCH: begin
                                                                address<=pc;
                                                                state<=`STATE_FETCH_OP;
                                                        end
                                                        `PRINTEFFECT_FETCHAFTER: begin
                                                                pc<=address;
                                                                state<=`STATE_FETCH_OP;
                                                        end
                                                        `PRINTEFFECT_RET1: begin
                                                                ReturnFunction(1);
                                                        end
                                                        `PRINTEFFECT_ABBREVRET: begin
                                                                address<=temp;
                                                                delayedValue<=operand[0];
                                                                phase<=operand[1];
                                                                returnValue[1:0]<=returnValue[3:2]; 
                                                        end
                                                endcase
                                        end else begin
                                                phase<=0;
                                        end
                                end
                                // branch to abbrev
                                6: begin
                                        address<='h18;
                                        phase<=phase+1;
                                        temp<=address;
                                        operand[0]<=delayedValue;
                                        returnValue[3:2]=returnValue[1:0];
                                        returnValue[1:0]=`PRINTEFFECT_ABBREVRET; 
                                end
                                7: begin address<=address+1; operand[2][7:0]=data; phase<=phase+1; end
                                8: begin address<=(operand[2][7:0]<<8)|data+2*store; phase<=phase+1; end
                                9: begin address<=address+1; operand[2][7:0]<=data; phase<=phase+1; end
                                default: begin address<=2*((operand[2][7:0]<<8)|data); phase<=0; end
                        endcase
`else
                        if (data[7] || returnValue[1:0]!=`PRINTEFFECT_FETCHAFTER) begin
                                if (returnValue[1:0]==`PRINTEFFECT_FETCHAFTER)
                                        pc<=address+2;
                                operand[0]<=`PRINT_CALLBACK; 
                                $display("Print from %h\n", temp);
                                operand[1]<=temp[0]|((returnValue[1:0]==`PRINTEFFECT_RET1)?2:0); operand[2]<=temp[16:1];
                                operTypes[1]=`OPER_LARGE; operTypes[2]=`OPER_LARGE;
                                CallFunction(returnValue[1:0]==`PRINTEFFECT_RET1, 1);
                        end else begin
                                address<=address+2;
                        end
`endif
                end
`ifdef HARDWARE_PRINT
                `STATE_PRINT_CHAR: begin
                        address<=pc;
                        printEnable<=0;
                        state<=`STATE_FETCH_OP;
                end
`endif
                default: begin
                        $display("HALT");
                        operand[1]<=(pc>>1);
                        operand[2]<=operand[0];
                        operand[3]<=operand[1];
                        operand[0]<=`EXCEPTION_CALLBACK;
                        //operTypes[0]<=`OPER_LARGE;
                        operTypes[1]<=`OPER_LARGE;
                        operTypes[2]<=`OPER_LARGE;
                        operTypes[3]<=`OPER_LARGE;
                        CallFunction(0,1);
                end
        endcase
end

endmodule

module main();

reg clk;
reg adcDout;
reg reset;
wire [7:0] data;
wire [16:0] address;
wire writeEnable;
wire printEnable;
wire romCS;
wire ramCS;
wire led0;
wire led1;
wire led2;
wire lcdCS;
wire lcdRS;
wire lcdReset;
wire adcCS;
wire a17;
wire a18;

integer file,readData,i,j,numOps,cycles,stateCycles[15:0],opCycles[255:0],ops[255:0];
integer touch,touchX, touchY, touchZ;
reg [7:0] mem [128*1024:0];
reg [7:0] dynamicMem [128*1024:0];

assign data=(!romCS ? mem[address] : (!ramCS ? (!writeEnable ? 8'bZ : dynamicMem[address] ) : 8'bZ ) );

initial
begin
        $display("Welcome");
        file=$fopen("rom.z3","rb");
        readData=$fread(mem, file);
        $display("File read:%h %d", file, readData);
        $fclose(file);
        touch=$fopen("touch.txt","r");
        adcDout=0;
        reset=1;
        numOps=0;
        cycles=0;
        mem['h1E57F]=1; // Suppress game select screen as it's slow
        for (i=0; i<16; i=i+1)
                stateCycles[i]=0;
        for (i=0; i<256; i=i+1) begin
                opCycles[i]=0;
                ops[i]=0;
        end
        //$monitor("%h %h %h State:%d(%d) Op:%h Num:%h OperType:%h%h%h%h OperIdx:%d Operand:%h %h Store:%h Branch:%h", clk, data, address, b.state, b.phase, b.op, b.operNum, b.operTypes[0], b.operTypes[1], b.operTypes[2], b.operTypes[3], b.operandIdx, b.operand[0], b.operand[1], b.store, b.branch);
        for (i=0; i</*505*/10000000; i=i+1) begin
                clk=1;
                #5 clk=0;
                if (!ramCS && !writeEnable) begin
                        dynamicMem[address]=data;
                end
`ifdef HARDWARE_PRINT
                if (!printEnable) begin
                        $display("PRINT: %c", data);
                end
`endif
                if (b.state==`STATE_HALT) begin
                        $display("Halt");
                        i=10000000;
                end
                if (b.operNum==`OP_VAR && b.op==`OPVAR_GETTOUCH && b.phase==0 && b.state==`STATE_DO_OP) begin
                        b.phase=3;
                        if ($fscanf(touch, "%d %d %d", touchX, touchY, touchZ)==-1) begin
                                i=10000000;
                        end
                        $display("Read: %d %d %d", touchX, touchY, touchZ);
                        case (b.operand[0])
                                'h93: b.operand[1]=touchZ;
                                'h95: b.operand[1]=touchX;
                                'h1A: b.operand[1]=touchY;
                                default: begin $display("Bad touch"); $finish; end
                        endcase
                end
                if (b.operNum==`OP_VAR && b.op==`OPVAR_BLIT1 && b.phase==0 && b.state==`STATE_DO_OP) begin
                        b.operand[1]=1;
                end
                //if (b.curPC<'h1e000)
                begin
                        if (b.state==`STATE_FETCH_OP) begin
                                ops[b.op+(32*b.operNum)]=ops[b.op+(32*b.operNum)]+1;
                                numOps=numOps+1;
                        end
                        if (b.state!=`STATE_RESET) begin
                                cycles=cycles+1;
                                opCycles[b.op+(32*b.operNum)]=opCycles[b.op+(32*b.operNum)]+1;
                        end
                        stateCycles[b.state]=stateCycles[b.state]+1;
                end
                $display("Mem req: %h WE:%d PE:%d%d%d%d RoS:%d RaS:%d D:%h LEDs:%d%d%d ADC:%d%d%d%d%d%d%d Ops:%d/%d", address, !writeEnable, printEnable, lcdCS, lcdRS, lcdReset, !romCS, !ramCS, data, !led0, !led1, !led2, !adcCS, address[0], address[1], lcdRS, printEnable, data[7], data[6], numOps, cycles);
        end
        for (i=0; i<16; i=i+1)
                if (stateCycles[i]>0)
                        $display("State:%d %d", i, stateCycles[i]);
        for (i=0; i<256; i=i+1)
                if (opCycles[i]>0)
                        $display("OpCyc:%d/%d %d/%d=%d", i/32, i%32, opCycles[i], ops[i], opCycles[i]/ops[i]);
        file=$fopen("ram.dat", "wb");
        for (i=0; i<'h20000; i=i+16) begin
                $fwrite(file, "%05h: ", i);
                for (j=0; j<16; j=j+2)
                        $fwrite(file, "%02x%02x ", dynamicMem[i+j][7:0], dynamicMem[i+j+1][7:0]);
                for (j=0; j<16; j=j+1)
                        $fwrite(file, "%c", (dynamicMem[i+j][7:0]>=32)?dynamicMem[i+j][7:0]:46);
                $fwrite(file, "\n");
        end
        $fwrite(file, "\nBitmap:\n");
        for (i='h1b500; i<'h20000; i=i+30) begin
                for (j=0; j<30; j=j+1)
                        $fwrite(file, "%d%d%d%d%d%d%d%d",
                dynamicMem[i+j][7], dynamicMem[i+j][6],
                dynamicMem[i+j][5], dynamicMem[i+j][4],
                dynamicMem[i+j][3], dynamicMem[i+j][2],
                dynamicMem[i+j][1], dynamicMem[i+j][0]);
                $fwrite(file, "\n");
        end
        $fclose(file);
        $fclose(touch);
        $finish;
end

boss b(clk, adcDout, reset, data, address, writeEnable, printEnable, romCS, ramCS, led0, led1, led2, lcdCS, lcdRS, lcdReset, adcCS, a17, a18);

endmodule

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.