aboutsummaryrefslogtreecommitdiffstats
path: root/src/eie2ugs/mips_cpu.cpp
blob: 475977ef4b89bcc057685a2447ab2a0453d0f14a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include "mips.h"

struct mips_cpu_impl
{
    uint32_t pc;
    uint32_t pcNext;
    
    uint32_t regs[32];
    
    mips_mem_h mem;
    
    unsigned logLevel;
    FILE *logDst;
};


mips_error mips_cpu_get_register(
	mips_cpu_h state,	//!< Valid (non-empty) handle to a CPU
	unsigned index,		//!< Index from 0 to 31
	uint32_t *value		//!< Where to write the value to
)
{
    // TODO : error handling
    *value = state->regs[index];
    return mips_Success;
}

/*! Modifies one of the 32 general purpose MIPS registers. */
mips_error mips_cpu_set_register(
	mips_cpu_h state,	//!< Valid (non-empty) handle to a CPU
	unsigned index,		//!< Index from 0 to 31
	uint32_t value		//!< New value to write into register file
)
{
    // TODO : error handling
    state->regs[index] = value;
    return mips_Success;
}

mips_error mips_cpu_set_debug_level(mips_cpu_h state, unsigned level, FILE *dest)
{
    state->logLevel = level;
    state->logDst = dest;
    return mips_Success;
}

mips_cpu_h mips_cpu_create(mips_mem_h mem)
{
    mips_cpu_impl *cpu=new mips_cpu_impl;
    
    cpu->pc=0;
    for(int i=0;i<32;i++){
        cpu->regs[i]=0;
    }
    cpu->mem=mem;
    
    return cpu;
}

/*! \param pData Array of 4 bytes
    \retval The big-endian equivlent
*/
uint32_t to_big(const uint8_t *pData)
{
    return
        (((uint32_t)pData[0])<<24)
        |
        (((uint32_t)pData[1])<<16)
        |
        (((uint32_t)pData[2])<<8)
        |
        (((uint32_t)pData[3])<<0);
}

mips_error mips_cpu_step(
	mips_cpu_h state	//! Valid (non-empty) handle to a CPU
)
{
    uint8_t buffer[4];
    
    mips_error err=mips_mem_read(
        state->mem,		//!< Handle to target memory
        state->pc,	//!< Byte address to start transaction at
        4,	//!< Number of bytes to transfer
        buffer	//!< Receives the target bytes
    );
    
    if(err!=0){
        return err;
    }
    
    uint32_t instruction= to_big(buffer);
    
    uint32_t opcode =  (instruction>>26) & 0x3F;
    uint32_t src1 = (instruction>> 21 ) & 0x1F;
    uint32_t src2 = (instruction>> 16 ) & 0x1F;   
    uint32_t dst = (instruction>> 11 ) & 0x1F;    
    uint32_t shift = (instruction>> 6 ) & 0x1F ;
    uint32_t function = (instruction>> 0 ) & 0x3F ;

    if(opcode == 0){
        // This is R-type
        if(state->logLevel >= 2){
            fprintf(state->logDst, "R-Type : dst=%u, src1=%u, src2=%u, shift=%u, function=%u.\n  instr=%08x\n",
                dst, src1, src2, shift, function, instruction
            );
        }
        
        if(function ==  0x21){
            if(state->logLevel >= 1){
                fprintf(state->logDst, "addu %u, %u, %u.\n", dst, src1, src2);
            }
            uint32_t va=state->regs[src1];
            uint32_t vb=state->regs[src2];
            
            uint32_t res=va+vb;
            
            state->regs[dst] = res; // NOTE: what about zero reg?
            
            // NOTE : What about updating the program counter
            return mips_Success;
        }else{
            return mips_ErrorNotImplemented;
        }
    }else{
        return mips_ErrorNotImplemented;
    }
}