From 800e11be161b404b7431ec7c96f6ef4c605a4083 Mon Sep 17 00:00:00 2001 From: "(Tim) Efthimis Kritikos" Date: Tue, 6 Feb 2024 23:14:33 +0000 Subject: [PATCH] CPU: Added support for conditional branches, HLT and NOP --- assembly.c | 12 ++++++++++++ cpu.c | 46 +++++++++++++++++++++++++++++++++++++++++----- cpu.h | 12 +++++++++++- gui.c | 28 ++++++++++++++++------------ gui.h | 2 +- main.c | 50 ++++++++++++++++++++++++++++++-------------------- simdata.c | 1 + simdata.h | 14 ++++++++++---- test.asm | 13 ++++++++----- 9 files changed, 130 insertions(+), 48 deletions(-) diff --git a/assembly.c b/assembly.c index bcdf244..212bd98 100644 --- a/assembly.c +++ b/assembly.c @@ -73,6 +73,8 @@ // | 13'd3 | SHIFT RIGHT | YES | // +-------+----------------------------------+--------------| // | 13'd4 | COMPARE (SUBTRACT WITHOUT SAVE) | YES | +// +-------+----------------------------------+--------------+ +// | 13'd5 | HALT | NO | // // // INSTRUCTION FORMAT 2 OPCODE NUM: @@ -146,6 +148,9 @@ char *disassemble(uint32_t opcode_be){ case 0x04: snprintf(ret,MAX_INSTRUCTION_LENGTH,"CMP %%R%0d, %%R%0d",val1,val2); break; + case 0x05: + snprintf(ret,MAX_INSTRUCTION_LENGTH,"HALT"); + break; default: snprintf(ret,MAX_INSTRUCTION_LENGTH,"UNRECOGNISED INSTRUCTION"); break; @@ -311,6 +316,13 @@ uint32_t assemble_line(char *line, __attribute__((unused)) struct assembler_cont return 0xFFFFFFFF; }else return 0xFFFFFFFF; + }else if(strncmp(line,"HALT",4)==0){ + x=4; + while(line[x]==' ')x++; + if(line[x]==0) + return 0x20050000; + else + return 0xFFFFFFFF; }else return 0xFFFFFFFF; } diff --git a/cpu.c b/cpu.c index 1e88d3b..9e22786 100644 --- a/cpu.c +++ b/cpu.c @@ -30,7 +30,21 @@ int decode(struct simdata_t *simdata){ case 0: opcode=(simdata->decode_data->in_bytecode&0x1F000000)>>24; switch(opcode){ + case 0: + simdata->exec_data->EXEC_ACTION=NOP; + break; case 1: + case 2: + case 3: + case 4: + case 5: + switch(opcode){ + case 1: simdata->exec_data->COND=NONE; break; + case 2: simdata->exec_data->COND=ZERO; break; + case 3: simdata->exec_data->COND=NZERO; break; + case 4: simdata->exec_data->COND=CARRY; break; + case 5: simdata->exec_data->COND=NCARRY; break; + } simdata->exec_data->out_op->OP_ADDR=IMMEDIATE; simdata->exec_data->out_op->data=simdata->decode_data->in_bytecode&0x00FFFFFF; simdata->exec_data->EXEC_ACTION=JUMP; @@ -51,7 +65,14 @@ int decode(struct simdata_t *simdata){ simdata->exec_data->in_op2->OP_ADDR=REGISTER; simdata->exec_data->in_op2->data=op2; - simdata->exec_data->EXEC_ACTION=EXEC_ALU; + switch(opcode){ + case 5: + simdata->exec_data->EXEC_ACTION=HALT; + break; + default: + simdata->exec_data->EXEC_ACTION=EXEC_ALU; + break; + } switch(opcode){ case 0: @@ -74,6 +95,7 @@ int decode(struct simdata_t *simdata){ case 2: simdata->exec_data->ALU_OP=ALU_SL; break; case 3: simdata->exec_data->ALU_OP=ALU_SR; break; case 4: simdata->exec_data->ALU_OP=ALU_CMP; break; + case 5: break; default: return 1; } @@ -144,10 +166,20 @@ void free_exec_data(struct exec_data_t *tofree){ int exec(struct simdata_t *simdata){ switch(simdata->exec_data->EXEC_ACTION){ case JUMP: - if(simdata->exec_data->out_op->OP_ADDR==IMMEDIATE) - simdata->PC=simdata->exec_data->out_op->data; - else - return 1; + int condition=0; + switch(simdata->exec_data->COND){ + case NONE: condition=1; break; + case ZERO: condition=simdata->registers->FLAGS&1; break; + case NZERO: condition=!(simdata->registers->FLAGS&1); break; + case CARRY: condition=simdata->registers->FLAGS&2; break; + case NCARRY: condition=!(simdata->registers->FLAGS&2); break; + } + if(condition){ + if(simdata->exec_data->out_op->OP_ADDR==IMMEDIATE) + simdata->PC=simdata->exec_data->out_op->data; + else + return 1; + } break; case EXEC_ALU: if( simdata->exec_data->in_op1->OP_ADDR==REGISTER && @@ -209,6 +241,10 @@ int exec(struct simdata_t *simdata){ default: return 1; } + case NOP: break; + case HALT: + simdata->cpu_state=CPU_HALTED; + break; } return 0; diff --git a/cpu.h b/cpu.h index 7ae544a..f903e7b 100644 --- a/cpu.h +++ b/cpu.h @@ -15,7 +15,9 @@ struct decode_data_t{ enum EXEC_ACTION_t { EXEC_ALU, MOVE, - JUMP + JUMP, + NOP, + HALT }; enum ALU_OP_t { @@ -38,10 +40,18 @@ struct exec_op_t { uint32_t data; }; +enum COND_t{ + NONE, + ZERO, + NZERO, + CARRY, + NCARRY +}; struct exec_data_t { enum EXEC_ACTION_t EXEC_ACTION; enum ALU_OP_t ALU_OP; + enum COND_t COND; struct exec_op_t *in_op1; struct exec_op_t *in_op2; struct exec_op_t *out_op; diff --git a/gui.c b/gui.c index 624fcbc..1b3ecb1 100644 --- a/gui.c +++ b/gui.c @@ -67,7 +67,7 @@ char *tab_name[]={"Overview","Memory","Internal"}; unsigned int CURRENT_TAB=0; -enum CPU_STATE_t CPU_STATE=SINGLE_STEPPING; +enum GUI_CPU_STATE_t CPU_STATE=GUI_CPU_SINGLE_STEPPING; void update_tabs(){ wattron(tabs,A_BOLD); @@ -94,15 +94,15 @@ void update_tabs(){ x+=strlen(tab_name[i])+2+3; } switch(CPU_STATE){ - case RUNNING: + case GUI_CPU_RUNNING: wattron(tabs,COLOR_PAIR(6)); mvwprintw(tabs,0,terminal_width-13,"[ RUNNING "); break; - case SINGLE_STEPPING: + case GUI_CPU_SINGLE_STEPPING: wattron(tabs,COLOR_PAIR(7)); mvwprintw(tabs,0,terminal_width-21,"[ SINGLE-STEPPING "); break; - case STOPPED: + case GUI_CPU_STOPPED: wattron(tabs,COLOR_PAIR(8)); mvwprintw(tabs,0,terminal_width-13,"[ STOPPED "); break; @@ -398,6 +398,8 @@ int update_general_registers(struct simdata_t *simdata){ int clear_back_window=1; int update_gui(struct simdata_t *simdata){ + if(simdata->cpu_state==CPU_HALTED) + CPU_STATE=GUI_CPU_STOPPED; if(clear_back_window){ clear(); clear_back_window=0; @@ -416,24 +418,26 @@ int update_gui(struct simdata_t *simdata){ return 0; } -int gui_continue_request(){ +int gui_continue_request(struct simdata_t *simdata){ char inch; int release=0; while(release==0){ if(((inch=getch())==ERR)){ - if(CPU_STATE==SINGLE_STEPPING) + if(CPU_STATE==GUI_CPU_SINGLE_STEPPING) return 1; else release=1; } switch(inch){ case 'r': - if(CPU_STATE==RUNNING){ - CPU_STATE=SINGLE_STEPPING; - nodelay(stdscr, FALSE); - }else{ - CPU_STATE=RUNNING; - nodelay(stdscr, TRUE); + if(simdata->cpu_state!=CPU_HALTED){ + if(CPU_STATE==GUI_CPU_RUNNING){ + CPU_STATE=GUI_CPU_SINGLE_STEPPING; + nodelay(stdscr, FALSE); + }else{ + CPU_STATE=GUI_CPU_RUNNING; + nodelay(stdscr, TRUE); + } } break; case 'q': diff --git a/gui.h b/gui.h index 8ace09c..aab1ff0 100644 --- a/gui.h +++ b/gui.h @@ -1,7 +1,7 @@ #include "simdata.h" int start_gui(); -int gui_continue_request(); +int gui_continue_request(struct simdata_t*); int end_gui(); int gui_error(char *); int update_gui(struct simdata_t *); diff --git a/main.c b/main.c index d70e3dc..7a2450a 100644 --- a/main.c +++ b/main.c @@ -25,6 +25,7 @@ #include #include "assembly.h" #include "cpu.h" +#include void help(char* progname){ printf("Usage: %s -i \n", progname); @@ -89,7 +90,13 @@ int main(int argc, char* argd[] ){ uint32_t opcode; uint32_t addr=0; while(fgets(line,sizeof(line),rom)!= NULL){ + + for(int i=0;line[i];i++) + if(line[i]==0x0a) + line[i]=0; + opcode=assemble_line(line,assembler_context); + if(opcode>0xFFFFFFF1){ printf("Error assembling %s:%d\n", infile,linec+1); fclose(rom); @@ -160,7 +167,7 @@ int main(int argc, char* argd[] ){ update_gui(simdata); int ret_code; - if((ret_code=gui_continue_request())){ + if((ret_code=gui_continue_request(simdata))){ if(ret_code==2) break; end_gui(); @@ -170,26 +177,29 @@ int main(int argc, char* argd[] ){ return 1; } - int ret; - if((ret=cpu_cycle_clock(simdata))){ - cpu_simdata_free(simdata); - free_simdata(simdata); - end_gui(); - switch(ret){ - case 1: - printf("Failed to execute instruction\n"); - break; - case 2: - printf("Failed to decode instruction\n"); - break; - case 3: - printf("Failed to fetch instruction\n"); - break; - default: - printf("Unkown CPU failure\n"); + if(simdata->cpu_state==CPU_RUNNING){ + int ret; + if((ret=cpu_cycle_clock(simdata))){ + cpu_simdata_free(simdata); + free_simdata(simdata); + end_gui(); + switch(ret){ + case 1: + printf("Failed to execute instruction\n"); + break; + case 2: + printf("Failed to decode instruction\n"); + break; + case 3: + printf("Failed to fetch instruction\n"); + break; + default: + printf("Unkown CPU failure\n"); + } + return 1; } - return 1; - } + }else + usleep(100000); } if(end_gui()){ diff --git a/simdata.c b/simdata.c index 76160c1..ecbd768 100644 --- a/simdata.c +++ b/simdata.c @@ -39,6 +39,7 @@ struct simdata_t *init_simdata(){ ret->PC=0; ret->SP=0; ret->registers=NULL; + ret->cpu_state=CPU_RUNNING; return ret; } diff --git a/simdata.h b/simdata.h index 5611fcf..733be2b 100644 --- a/simdata.h +++ b/simdata.h @@ -1,6 +1,11 @@ #ifndef SIMDATA_HEADER #include +enum CPU_STATE_t{ + CPU_RUNNING, + CPU_HALTED +}; + struct simdata_t{ long unsigned int current_clock; uint8_t *RAM; @@ -10,16 +15,17 @@ struct simdata_t{ struct decode_data_t *decode_data; struct exec_data_t *exec_data; struct registers_t *registers; + enum CPU_STATE_t cpu_state; }; struct simdata_t *init_simdata(); void free_simdata(struct simdata_t *); -enum CPU_STATE_t{ - RUNNING, - SINGLE_STEPPING, - STOPPED +enum GUI_CPU_STATE_t{ + GUI_CPU_RUNNING, + GUI_CPU_SINGLE_STEPPING, + GUI_CPU_STOPPED }; #endif diff --git a/test.asm b/test.asm index 4f42000..11dd054 100644 --- a/test.asm +++ b/test.asm @@ -1,7 +1,10 @@ -MOV $0000,%R0l -MOV $8000,%R0h +MOV $0001,%R0l +MOV $0000,%R0h MOV $0001,%R1l MOV $0000,%R1h -CMP %R1,%R0 -SR %R0,%R1 -JMP $000014 +MOV $0010,%R2l +MOV $0000,%R2h +ADD %R0,%R1 +CMP %R1,%R2 +JMP,NZ $000018 +HALT