nemu/src/cpu.c

336 lines
16 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <cpu.h>
#include <log.h>
#include <instructions/instructions.h>
#include <display.h>
uint32_t decode(unsigned char a,unsigned char b,unsigned char c,unsigned char d)
{
return ((uint32_t)d << 24) | ((uint32_t)c << 16) | ((uint32_t)b << 8) | (uint32_t)a;
}
uint16_t decode16(unsigned char a,unsigned char b)
{
return ((uint16_t)b << 8) | (uint16_t)a;
}
int cpu_setup_addin(cpu_status_t* status,char* _file){
FILE * addin_file;
addin_file = fopen(_file, "rb");
if(addin_file == NULL){
return 1;
}
printf("file: %s\n",_file);
fseek(addin_file, 0L, SEEK_END);
status->program_size = ftell(addin_file) - 0x200L;
status->rom = malloc(status->program_size);
fseek(addin_file, 0x200L,SEEK_SET);
fread(status->rom, status->program_size, 1, addin_file);
fclose(addin_file);
printf("%d bytes allocated\n",status->program_size);
status->pc = 0x00300200;
for(int i=0; i<32768; i++){
status->ram[i] = 0x00;
}
status->display = malloc(sizeof(display_t));
display_init(status->display);
display_clear(status->display);
status->malloc.lo_mem = 0x08100000 + 32768;
status->malloc.hi_mem = 0x08100000 + 524288 - 16384;
status->malloc.margin = 0x200;
status->malloc.allocs = 0;
status->malloc.mallocs = malloc(0);
}
int cpu_run(cpu_status_t* status){
}
uint32_t cpu_read32(cpu_status_t* status, uint32_t addr){
if(addr >=0x08100000 && addr <= 0x08100000+524288){
uint32_t ret;
ret = decode(status->ram[addr-0x08100000+3], status->ram[addr-0x08100000+2], status->ram[addr-0x08100000+1], status->ram[addr-0x08100000]);
return ret;
}
else if(addr >=0x00300200 && addr <= 0x00300200+status->program_size){
uint32_t ret;
ret = decode(status->rom[addr-0x00300200+3], status->rom[addr-0x00300200+2], status->rom[addr-0x00300200+1], status->rom[addr-0x00300200]);
return ret;
}
else{
log_mem_read_error(status, addr);
return 0;
}
}
uint16_t cpu_read16(cpu_status_t* status, uint32_t addr){
if(addr >=0x08100000 && addr <= 0x08100000+524288){
uint16_t ret;
//ret = (uint16_t)status->ram[addr-0x08100000];
ret = status->ram[addr-0x08100000];
ret <<= 8;
ret |= status->ram[addr-0x08100000+1];
return ret;
}
else if(addr >=0x00300200 && addr <= 0x00300200+status->program_size){
uint16_t ret;
ret = status->rom[addr-0x00300200];
ret <<= 8;
ret |= status->rom[addr-0x00300200+1];
//memcpy(&ret,&status->ram[addr-0x00300000],1);
//ret = (uint16_t)status->rom[addr-0x00300000];
return ret;
}
else{
log_mem_read_error(status, addr);
return 0;
}
}
uint8_t cpu_read8(cpu_status_t* status, uint32_t addr){
if(addr >=0x08100000 && addr <= 0x08100000+524288){
uint8_t ret;
ret = status->ram[addr-0x08100000];
return ret;
}
else if(addr >=0x00300200 && addr <= 0x00300200+status->program_size){
uint8_t ret;
ret = status->rom[addr-0x00300200];
return ret;
}
else if(addr >=0x01100000 && addr <= 0x01100000+8192){
uint8_t ret;
ret = status->vram[addr-0x01100000];
return ret;
}
else{
log_mem_read_error(status, addr);
return 8;
}
}
void cpu_write32(cpu_status_t* status, uint32_t addr, uint32_t data){
if(addr >=0x08100000 && addr <= 0x08100000+524288){
unsigned char bytes[4];
status->ram[addr-0x08100000] = (data >> 24) & 0xFF;
status->ram[addr-0x08100000+1] = (data >> 16) & 0xFF;
status->ram[addr-0x08100000+2] = (data >> 8) & 0xFF;
status->ram[addr-0x08100000+3] = data & 0xFF;
}
/*else if(addr >=0x00300200 && addr <= 0x00300200+status->program_size){
memcpy(&status->rom[addr-0x00300200], &addr, 4);
}*/
else if(addr >=0x01100000 && addr <= 0x01100000+8192){
status->vram[addr-0x01100000] = (data >> 24) & 0xFF;
status->vram[addr-0x01100000+1] = (data >> 16) & 0xFF;
status->vram[addr-0x01100000+2] = (data >> 8) & 0xFF;
status->vram[addr-0x01100000+3] = data & 0xFF;
display_update(status->display, status);
}
else{
log_mem_write_error(status, addr);
}
}
void cpu_write16(cpu_status_t* status, uint32_t addr, uint16_t data){
if(addr >=0x08100000 && addr <= 0x08100000+524288){
memcpy(&status->ram[addr-0x08100000],&data, 2);
}
/*else if(addr >=0x00300200 && addr <= 0x00300200+status->program_size){
memcpy(&status->rom[addr-0x00300200], &addr, 2);
}*/
else if(addr == 0xa4000102 || addr == 0xa4000118){
}
else{
log_mem_write_error(status, addr);
}
}
void cpu_write8(cpu_status_t* status, uint32_t addr, uint8_t data){
if(addr >=0x08100000 && addr <= 0x08100000+524288){
status->ram[addr-0x08100000] = data;
}
/*else if(addr >=0x00300200 && addr <= 0x00300200+status->program_size){
status->rom[addr-0x00300200] = data;
}*/
else if(addr >=0x01100000 && addr <= 0x01100000+8192){
status->vram[addr-0x01100000] = data;
}
else if(addr == 0xb4000000 || addr == 0xb4010000){
}
else{
log_mem_write_error(status, addr);
}
}
int cpu_execute(cpu_status_t* status){
char nibble[4] = {
HI_NIBBLE(cpu_read8(status,status->pc)),
LO_NIBBLE(cpu_read8(status,status->pc)),
HI_NIBBLE(cpu_read8(status,status->pc+1)),
LO_NIBBLE(cpu_read8(status,status->pc+1))
};
/*printf("pc: %8x pr: %8x r0: %8x r1: %8x r2: %8x r3: %8x r4: %8x r5: %8x r6: %8x r15: %08x\n",
status->pc,status->pr,
status->r[0],status->r[1],status->r[2],status->r[3],
status->r[4],status->r[5],status->r[6],status->r[15]
);*/
/*printf("pc: %8x %02x%02x pr: %8x r0: %8x r1: %8x r2: %8x r3: %8x r4: %8x r5: %8x r6: %8x r7: %8x r8: %8x r9: %8x r15: %08x\n",
status->pc,cpu_read8(status,status->pc),cpu_read8(status,status->pc+1), status->pr,
status->r[0],status->r[1],status->r[2],status->r[3],
status->r[4],status->r[5],status->r[6],
status->r[7],status->r[8],status->r[9],
status->r[15]
);*/
if(nibble[0] == 0b0110 && nibble[3] == 0b0011) instruction_mov_r_r(status);
else if(nibble[0] == 0b1110) instruction_mov_imm_r(status);
else if(nibble[0] == 0b0000 && nibble[2] == 0b0010 && nibble[3] == 0b1001) instruction_movt_r(status);
else if(nibble[0] == 0b0110 && nibble[3] == 0b1000) instruction_swapb_r_r(status);
else if(nibble[0] == 0b1101) instruction_movl_disp_pc_r(status);
else if(nibble[0] == 0b0110 && nibble[3] == 0b0010) instruction_movl_ar_r(status);
else if(nibble[0] == 0b0010 && nibble[3] == 0b0010) instruction_movl_r_ar(status);
else if(nibble[0] == 0b0110 && nibble[3] == 0b0110) instruction_movl_arp_r(status);
else if(nibble[0] == 0b0010 && nibble[3] == 0b0110) instruction_movl_r_amr(status);
else if(nibble[0] == 0b0101) instruction_movl_disp_r_r(status);
else if(nibble[0] == 0b0001) instruction_movl_r_disp_r(status);
else if(nibble[0] == 0b0000 && nibble[3] == 0b1110) instruction_movl_r0_r_r(status);
else if(nibble[0] == 0b0000 && nibble[3] == 0b0110) instruction_movl_r_r0_r(status);
else if(nibble[0] == 0b1100 && nibble[1] == 0b0110) instruction_movl_disp_gbr_r0(status);
else if(nibble[0] == 0b1000 && nibble[1] == 0b0001) instruction_movw_r0_disp_r(status);
else if(nibble[0] == 0b1000 && nibble[1] == 0b0101) instruction_movw_disp_r_r0(status);
else if(nibble[0] == 0b1001) instruction_movw_disp_pc_r0(status);
else if(nibble[0] == 0b0010 && nibble[3] == 0b0001) instruction_movw_r_ar(status);
else if(nibble[0] == 0b0110 && nibble[3] == 0b0101) instruction_movw_arp_r(status);
else if(nibble[0] == 0b1100 && nibble[1] == 0b0001) instruction_movw_r0_disp_gbr(status);
else if(nibble[0] == 0b0110 && nibble[3] == 0b0001) instruction_movw_ar_r(status);
else if(nibble[0] == 0b0000 && nibble[3] == 0b1101) instruction_movw_r0_r_r(status);
else if(nibble[0] == 0b1100 && nibble[1] == 0b0101) instruction_movw_disp_gbr_r0(status);
else if(nibble[0] == 0b0110 && nibble[3] == 0b0000) instruction_movb_ar_r(status);
else if(nibble[0] == 0b0010 && nibble[3] == 0b0000) instruction_movb_r_ar(status);
else if(nibble[0] == 0b0110 && nibble[3] == 0b0100) instruction_movb_arp_r(status);
else if(nibble[0] == 0b0010 && nibble[3] == 0b0100) instruction_movb_r_amr(status);
else if(nibble[0] == 0b1000 && nibble[1] == 0b0100) instruction_movb_disp_r_r0(status);
else if(nibble[0] == 0b0000 && nibble[3] == 0b1100) instruction_movb_r0_r_r(status);
else if(nibble[0] == 0b0000 && nibble[3] == 0b0100) instruction_movb_r_r0_r(status);
else if(nibble[0] == 0b1100 && nibble[1] == 0b0100) instruction_movb_disp_gbr_r0(status);
else if(nibble[0] == 0b1000 && nibble[1] == 0b0000) instruction_movb_r0_disp_r(status);
else if(nibble[0] == 0b1100 && nibble[1] == 0b0000) instruction_movb_r0_disp_gbr(status);
else if(nibble[0] == 0b0100 && nibble[2] == 0b0010 && nibble[3] == 0b0100) instruction_roctl_r(status);
else if(nibble[0] == 0b0100 && nibble[2] == 0b0010 && nibble[3] == 0b0001) instruction_shar_r(status);
else if(nibble[0] == 0b0100 && nibble[2] == 0b0000 && nibble[3] == 0b1000) instruction_shll2_r(status);
else if(nibble[0] == 0b0100 && nibble[2] == 0b0000 && nibble[3] == 0b0001) instruction_shlr_r(status);
else if(nibble[0] == 0b0100 && nibble[2] == 0b0000 && nibble[3] == 0b1001) instruction_shlr2_r(status);
else if(nibble[0] == 0b0100 && nibble[3] == 0b1101) instruction_shld_r_r(status);
else if(nibble[0] == 0b0100 && nibble[2] == 0b0000 && nibble[3] == 0b0000) instruction_shll_r(status);
else if(nibble[0] == 0b0100 && nibble[2] == 0b0010 && nibble[3] == 0b1000) instruction_shll16_r(status);
else if(nibble[0] == 0b0100 && nibble[2] == 0b0001 && nibble[3] == 0b1000) instruction_shll8_r(status);
else if(nibble[0] == 0b0100 && nibble[2] == 0b0010 && nibble[3] == 0b0101) instruction_rotcr_r(status);
else if(nibble[0] == 0b0100 && nibble[3] == 0b1100) instruction_shad_r_r(status);
else if(nibble[0] == 0b0100 && nibble[2] == 0b0010 && nibble[3] == 0b1001) instruction_shlr16_r(status);
else if(nibble[0] == 0b0100 && nibble[2] == 0b0001 && nibble[3] == 0b1001) instruction_shlr8_r(status);
else if(nibble[0] == 0b0011 && nibble[3] == 0b0100) instruction_div1_r_r(status);
else if(nibble[0] == 0b0011 && nibble[3] == 0b1100) instruction_add_r_r(status);
else if(nibble[0] == 0b0111) instruction_add_imm_r(status);
else if(nibble[0] == 0b0100 && nibble[2] == 0b0001 && nibble[3] == 0b0001) instruction_cmp_pz_r(status);
else if(nibble[0] == 0b0011 && nibble[3] == 0b0111) instruction_cmp_gt_r_r(status);
else if(nibble[0] == 0b0011 && nibble[3] == 0b0010) instruction_cmp_hs_r_r(status);
else if(nibble[0] == 0b0011 && nibble[3] == 0b1000) instruction_sub_r_r(status);
else if(nibble[0] == 0b0110 && nibble[3] == 0b1101) instruction_extuw_r_r(status);
else if(nibble[0] == 0b0100 && nibble[2] == 0b0001 && nibble[3] == 0b0101) instruction_cmp_pl_r(status);
else if(nibble[0] == 0b1000 && nibble[1] == 0b1000) instruction_cmp_eq_imm_r0(status);
else if(nibble[0] == 0b0011 && nibble[3] == 0b0110) instruction_cmp_hi_r_r(status);
else if(nibble[0] == 0b0011 && nibble[3] == 0b0011) instruction_cmp_ge_r_r(status);
else if(nibble[0] == 0b0000 && nibble[3] == 0b0111) instruction_mull_r_r(status);
else if(nibble[0] == 0b0011 && nibble[3] == 0b0000) instruction_cmp_eq_r_r(status);
else if(nibble[0] == 0b0110 && nibble[3] == 0b1100) instruction_extub_r_r(status);
else if(nibble[0] == 0b0100 && nibble[2] == 0b0001 && nibble[3] == 0b0000) instruction_dt_r(status);
else if(nibble[0] == 0b0010 && nibble[3] == 0b0111) instruction_div0s_r_r(status);
else if(nibble[0] == 0b0011 && nibble[3] == 0b1110) instruction_addc_r_r(status);
else if(nibble[0] == 0b0011 && nibble[3] == 0b1010) instruction_subc_r_r(status);
else if(nibble[0] == 0b0110 && nibble[3] == 0b1110) instruction_extsb_r_r(status);
else if(nibble[0] == 0b0110 && nibble[3] == 0b1011) instruction_neg_r_r(status);
else if(nibble[0] == 0b0010 && nibble[3] == 0b1100) instruction_cmp_str_r_r(status);
else if(nibble[0] == 0b0100 && nibble[2] == 0b0010 && nibble[3] == 0b1011) instruction_jmp_r(status);
else if(nibble[0] == 0b1011) instruction_bsr_lbl(status);
else if(nibble[0] == 0b0100 && nibble[2] == 0b0000 && nibble[3] == 0b1011) instruction_jsr_ar(status);
else if(nibble[0] == 0b0000 && nibble[1] == 0b0000 && nibble[2] == 0b0000 && nibble[3] == 0b1011) instruction_rts(status);
else if(cpu_read8(status,status->pc) == 0x00 && cpu_read8(status,status->pc+1) == 0x0b) instruction_rts(status);
else if(nibble[0] == 0b1000 && nibble[1] == 0b1011 ) instruction_bf_lbl(status);
else if(nibble[0] == 0b1010) instruction_bra_lbl(status);
else if(nibble[0] == 0b1000 && nibble[1] == 0b1001 ) instruction_bt_lbl(status);
else if(nibble[0] == 0b1000 && nibble[1] == 0b1101 ) instruction_bts_lbl(status);
else if(nibble[0] == 0b1000 && nibble[1] == 0b1111 ) instruction_bfs_lbl(status);
else if(nibble[0] == 0b0000 && nibble[1] == 0b0000 && nibble[2] == 0b0000 && nibble[3] == 0b1001) instruction_nop(status);
else if(nibble[0] == 0b0100 && nibble[2] == 0b0000 && nibble[3] == 0b0010) instruction_stsl_mash_amr(status);
else if(nibble[0] == 0b0100 && nibble[2] == 0b0001 && nibble[3] == 0b0010) instruction_stsl_macl_amr(status);
else if(nibble[0] == 0b0100 && nibble[2] == 0b0010 && nibble[3] == 0b0010) instruction_stsl_pr_amr(status);
else if(nibble[0] == 0b0000 && nibble[1] == 0b0000 && nibble[2] == 0b0000 && nibble[3] == 0b1000) instruction_clrt(status);
else if(nibble[0] == 0b0100 && nibble[2] == 0b0010 && nibble[3] == 0b0110) instruction_ldsl_arp_pr(status);
else if(nibble[0] == 0b0100 && nibble[2] == 0b0001 && nibble[3] == 0b0110) instruction_ldsl_arp_macl(status);
else if(nibble[0] == 0b0000 && nibble[2] == 0b0001 && nibble[3] == 0b1010) instruction_sts_macl_r(status);
else if(nibble[0] == 0b0100 && nibble[2] == 0b0001 && nibble[3] == 0b1110) instruction_ldc_r_gbr(status);
else if(nibble[0] == 0b0000 && nibble[2] == 0b0001 && nibble[3] == 0b0010) instruction_stc_gbr_r(status);
else if(nibble[0] == 0b0010 && nibble[3] == 0b1000) instruction_tst_r_r(status);
else if(nibble[0] == 0b0010 && nibble[3] == 0b1011) instruction_or_r_r(status);
else if(nibble[0] == 0b0010 && nibble[3] == 0b1001) instruction_and_r_r(status);
else if(nibble[0] == 0b0010 && nibble[3] == 0b1010) instruction_xor_r_r(status);
else if(nibble[0] == 0b1100 && nibble[1] == 0b1001) instruction_and_imm_r0(status);
else if(nibble[0] == 0b0110 && nibble[3] == 0b0111) instruction_not_r_r(status);
else if(nibble[0] == 0b1100 && nibble[1] == 0b1011) instruction_or_imm_r0(status);
else{ printf("\e[33mpc: %8x unkdown opcode, skipping...\e[39m\n",status->pc);status->pc += 2;exit(1);return 1;}
return 0;
}
int cpu_run_from(cpu_status_t* status, uint32_t addr){
status->pc = addr;
int total_error = 0;
int total_executions = 0;
//while (status->pc-0x00300200 < status->program_size){
while (status->pc-0x00300200 < status->program_size || ( status->pc >= 0x08100000 && status->pc <= 0x08100000+524288 )){
// TODO: better kerboard gestion
SDL_PumpEvents();
const unsigned char* key = SDL_GetKeyboardState(NULL);
if (key[SDL_SCANCODE_ESCAPE]) {
exit(0);
}
if(cpu_execute(status)){
total_error++;
}
//total_executions++;
/*if(total_executions > 100000){
break;
}*/
}
printf("excution terminated with %d not found opcodes\n",total_error);
}