CPU: Added support for conditional branches, HLT and NOP

This commit is contained in:
(Tim) Efthimis Kritikos 2024-02-06 23:14:33 +00:00
parent 1dcc69ba50
commit 800e11be16
9 changed files with 130 additions and 48 deletions

View File

@ -73,6 +73,8 @@
// | 13'd3 | SHIFT RIGHT | YES | // | 13'd3 | SHIFT RIGHT | YES |
// +-------+----------------------------------+--------------| // +-------+----------------------------------+--------------|
// | 13'd4 | COMPARE (SUBTRACT WITHOUT SAVE) | YES | // | 13'd4 | COMPARE (SUBTRACT WITHOUT SAVE) | YES |
// +-------+----------------------------------+--------------+
// | 13'd5 | HALT | NO |
// //
// //
// INSTRUCTION FORMAT 2 OPCODE NUM: // INSTRUCTION FORMAT 2 OPCODE NUM:
@ -146,6 +148,9 @@ char *disassemble(uint32_t opcode_be){
case 0x04: case 0x04:
snprintf(ret,MAX_INSTRUCTION_LENGTH,"CMP %%R%0d, %%R%0d",val1,val2); snprintf(ret,MAX_INSTRUCTION_LENGTH,"CMP %%R%0d, %%R%0d",val1,val2);
break; break;
case 0x05:
snprintf(ret,MAX_INSTRUCTION_LENGTH,"HALT");
break;
default: default:
snprintf(ret,MAX_INSTRUCTION_LENGTH,"UNRECOGNISED INSTRUCTION"); snprintf(ret,MAX_INSTRUCTION_LENGTH,"UNRECOGNISED INSTRUCTION");
break; break;
@ -311,6 +316,13 @@ uint32_t assemble_line(char *line, __attribute__((unused)) struct assembler_cont
return 0xFFFFFFFF; return 0xFFFFFFFF;
}else }else
return 0xFFFFFFFF; 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 }else
return 0xFFFFFFFF; return 0xFFFFFFFF;
} }

46
cpu.c
View File

@ -30,7 +30,21 @@ int decode(struct simdata_t *simdata){
case 0: case 0:
opcode=(simdata->decode_data->in_bytecode&0x1F000000)>>24; opcode=(simdata->decode_data->in_bytecode&0x1F000000)>>24;
switch(opcode){ switch(opcode){
case 0:
simdata->exec_data->EXEC_ACTION=NOP;
break;
case 1: 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->OP_ADDR=IMMEDIATE;
simdata->exec_data->out_op->data=simdata->decode_data->in_bytecode&0x00FFFFFF; simdata->exec_data->out_op->data=simdata->decode_data->in_bytecode&0x00FFFFFF;
simdata->exec_data->EXEC_ACTION=JUMP; 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->OP_ADDR=REGISTER;
simdata->exec_data->in_op2->data=op2; 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){ switch(opcode){
case 0: case 0:
@ -74,6 +95,7 @@ int decode(struct simdata_t *simdata){
case 2: simdata->exec_data->ALU_OP=ALU_SL; break; case 2: simdata->exec_data->ALU_OP=ALU_SL; break;
case 3: simdata->exec_data->ALU_OP=ALU_SR; break; case 3: simdata->exec_data->ALU_OP=ALU_SR; break;
case 4: simdata->exec_data->ALU_OP=ALU_CMP; break; case 4: simdata->exec_data->ALU_OP=ALU_CMP; break;
case 5: break;
default: default:
return 1; return 1;
} }
@ -144,10 +166,20 @@ void free_exec_data(struct exec_data_t *tofree){
int exec(struct simdata_t *simdata){ int exec(struct simdata_t *simdata){
switch(simdata->exec_data->EXEC_ACTION){ switch(simdata->exec_data->EXEC_ACTION){
case JUMP: case JUMP:
if(simdata->exec_data->out_op->OP_ADDR==IMMEDIATE) int condition=0;
simdata->PC=simdata->exec_data->out_op->data; switch(simdata->exec_data->COND){
else case NONE: condition=1; break;
return 1; 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; break;
case EXEC_ALU: case EXEC_ALU:
if( simdata->exec_data->in_op1->OP_ADDR==REGISTER && if( simdata->exec_data->in_op1->OP_ADDR==REGISTER &&
@ -209,6 +241,10 @@ int exec(struct simdata_t *simdata){
default: default:
return 1; return 1;
} }
case NOP: break;
case HALT:
simdata->cpu_state=CPU_HALTED;
break;
} }
return 0; return 0;

12
cpu.h
View File

@ -15,7 +15,9 @@ struct decode_data_t{
enum EXEC_ACTION_t { enum EXEC_ACTION_t {
EXEC_ALU, EXEC_ALU,
MOVE, MOVE,
JUMP JUMP,
NOP,
HALT
}; };
enum ALU_OP_t { enum ALU_OP_t {
@ -38,10 +40,18 @@ struct exec_op_t {
uint32_t data; uint32_t data;
}; };
enum COND_t{
NONE,
ZERO,
NZERO,
CARRY,
NCARRY
};
struct exec_data_t { struct exec_data_t {
enum EXEC_ACTION_t EXEC_ACTION; enum EXEC_ACTION_t EXEC_ACTION;
enum ALU_OP_t ALU_OP; enum ALU_OP_t ALU_OP;
enum COND_t COND;
struct exec_op_t *in_op1; struct exec_op_t *in_op1;
struct exec_op_t *in_op2; struct exec_op_t *in_op2;
struct exec_op_t *out_op; struct exec_op_t *out_op;

28
gui.c
View File

@ -67,7 +67,7 @@ char *tab_name[]={"Overview","Memory","Internal"};
unsigned int CURRENT_TAB=0; 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(){ void update_tabs(){
wattron(tabs,A_BOLD); wattron(tabs,A_BOLD);
@ -94,15 +94,15 @@ void update_tabs(){
x+=strlen(tab_name[i])+2+3; x+=strlen(tab_name[i])+2+3;
} }
switch(CPU_STATE){ switch(CPU_STATE){
case RUNNING: case GUI_CPU_RUNNING:
wattron(tabs,COLOR_PAIR(6)); wattron(tabs,COLOR_PAIR(6));
mvwprintw(tabs,0,terminal_width-13,"[ RUNNING "); mvwprintw(tabs,0,terminal_width-13,"[ RUNNING ");
break; break;
case SINGLE_STEPPING: case GUI_CPU_SINGLE_STEPPING:
wattron(tabs,COLOR_PAIR(7)); wattron(tabs,COLOR_PAIR(7));
mvwprintw(tabs,0,terminal_width-21,"[ SINGLE-STEPPING "); mvwprintw(tabs,0,terminal_width-21,"[ SINGLE-STEPPING ");
break; break;
case STOPPED: case GUI_CPU_STOPPED:
wattron(tabs,COLOR_PAIR(8)); wattron(tabs,COLOR_PAIR(8));
mvwprintw(tabs,0,terminal_width-13,"[ STOPPED "); mvwprintw(tabs,0,terminal_width-13,"[ STOPPED ");
break; break;
@ -398,6 +398,8 @@ int update_general_registers(struct simdata_t *simdata){
int clear_back_window=1; int clear_back_window=1;
int update_gui(struct simdata_t *simdata){ int update_gui(struct simdata_t *simdata){
if(simdata->cpu_state==CPU_HALTED)
CPU_STATE=GUI_CPU_STOPPED;
if(clear_back_window){ if(clear_back_window){
clear(); clear();
clear_back_window=0; clear_back_window=0;
@ -416,24 +418,26 @@ int update_gui(struct simdata_t *simdata){
return 0; return 0;
} }
int gui_continue_request(){ int gui_continue_request(struct simdata_t *simdata){
char inch; char inch;
int release=0; int release=0;
while(release==0){ while(release==0){
if(((inch=getch())==ERR)){ if(((inch=getch())==ERR)){
if(CPU_STATE==SINGLE_STEPPING) if(CPU_STATE==GUI_CPU_SINGLE_STEPPING)
return 1; return 1;
else else
release=1; release=1;
} }
switch(inch){ switch(inch){
case 'r': case 'r':
if(CPU_STATE==RUNNING){ if(simdata->cpu_state!=CPU_HALTED){
CPU_STATE=SINGLE_STEPPING; if(CPU_STATE==GUI_CPU_RUNNING){
nodelay(stdscr, FALSE); CPU_STATE=GUI_CPU_SINGLE_STEPPING;
}else{ nodelay(stdscr, FALSE);
CPU_STATE=RUNNING; }else{
nodelay(stdscr, TRUE); CPU_STATE=GUI_CPU_RUNNING;
nodelay(stdscr, TRUE);
}
} }
break; break;
case 'q': case 'q':

2
gui.h
View File

@ -1,7 +1,7 @@
#include "simdata.h" #include "simdata.h"
int start_gui(); int start_gui();
int gui_continue_request(); int gui_continue_request(struct simdata_t*);
int end_gui(); int end_gui();
int gui_error(char *); int gui_error(char *);
int update_gui(struct simdata_t *); int update_gui(struct simdata_t *);

50
main.c
View File

@ -25,6 +25,7 @@
#include <errno.h> #include <errno.h>
#include "assembly.h" #include "assembly.h"
#include "cpu.h" #include "cpu.h"
#include <unistd.h>
void help(char* progname){ void help(char* progname){
printf("Usage: %s -i <file> \n", progname); printf("Usage: %s -i <file> \n", progname);
@ -89,7 +90,13 @@ int main(int argc, char* argd[] ){
uint32_t opcode; uint32_t opcode;
uint32_t addr=0; uint32_t addr=0;
while(fgets(line,sizeof(line),rom)!= NULL){ 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); opcode=assemble_line(line,assembler_context);
if(opcode>0xFFFFFFF1){ if(opcode>0xFFFFFFF1){
printf("Error assembling %s:%d\n", infile,linec+1); printf("Error assembling %s:%d\n", infile,linec+1);
fclose(rom); fclose(rom);
@ -160,7 +167,7 @@ int main(int argc, char* argd[] ){
update_gui(simdata); update_gui(simdata);
int ret_code; int ret_code;
if((ret_code=gui_continue_request())){ if((ret_code=gui_continue_request(simdata))){
if(ret_code==2) if(ret_code==2)
break; break;
end_gui(); end_gui();
@ -170,26 +177,29 @@ int main(int argc, char* argd[] ){
return 1; return 1;
} }
int ret; if(simdata->cpu_state==CPU_RUNNING){
if((ret=cpu_cycle_clock(simdata))){ int ret;
cpu_simdata_free(simdata); if((ret=cpu_cycle_clock(simdata))){
free_simdata(simdata); cpu_simdata_free(simdata);
end_gui(); free_simdata(simdata);
switch(ret){ end_gui();
case 1: switch(ret){
printf("Failed to execute instruction\n"); case 1:
break; printf("Failed to execute instruction\n");
case 2: break;
printf("Failed to decode instruction\n"); case 2:
break; printf("Failed to decode instruction\n");
case 3: break;
printf("Failed to fetch instruction\n"); case 3:
break; printf("Failed to fetch instruction\n");
default: break;
printf("Unkown CPU failure\n"); default:
printf("Unkown CPU failure\n");
}
return 1;
} }
return 1; }else
} usleep(100000);
} }
if(end_gui()){ if(end_gui()){

View File

@ -39,6 +39,7 @@ struct simdata_t *init_simdata(){
ret->PC=0; ret->PC=0;
ret->SP=0; ret->SP=0;
ret->registers=NULL; ret->registers=NULL;
ret->cpu_state=CPU_RUNNING;
return ret; return ret;
} }

View File

@ -1,6 +1,11 @@
#ifndef SIMDATA_HEADER #ifndef SIMDATA_HEADER
#include <stdint.h> #include <stdint.h>
enum CPU_STATE_t{
CPU_RUNNING,
CPU_HALTED
};
struct simdata_t{ struct simdata_t{
long unsigned int current_clock; long unsigned int current_clock;
uint8_t *RAM; uint8_t *RAM;
@ -10,16 +15,17 @@ struct simdata_t{
struct decode_data_t *decode_data; struct decode_data_t *decode_data;
struct exec_data_t *exec_data; struct exec_data_t *exec_data;
struct registers_t *registers; struct registers_t *registers;
enum CPU_STATE_t cpu_state;
}; };
struct simdata_t *init_simdata(); struct simdata_t *init_simdata();
void free_simdata(struct simdata_t *); void free_simdata(struct simdata_t *);
enum CPU_STATE_t{ enum GUI_CPU_STATE_t{
RUNNING, GUI_CPU_RUNNING,
SINGLE_STEPPING, GUI_CPU_SINGLE_STEPPING,
STOPPED GUI_CPU_STOPPED
}; };
#endif #endif

View File

@ -1,7 +1,10 @@
MOV $0000,%R0l MOV $0001,%R0l
MOV $8000,%R0h MOV $0000,%R0h
MOV $0001,%R1l MOV $0001,%R1l
MOV $0000,%R1h MOV $0000,%R1h
CMP %R1,%R0 MOV $0010,%R2l
SR %R0,%R1 MOV $0000,%R2h
JMP $000014 ADD %R0,%R1
CMP %R1,%R2
JMP,NZ $000018
HALT