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'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;
}

36
cpu.c
View File

@ -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;
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:
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;

12
cpu.h
View File

@ -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;

22
gui.c
View File

@ -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,25 +418,27 @@ 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;
if(simdata->cpu_state!=CPU_HALTED){
if(CPU_STATE==GUI_CPU_RUNNING){
CPU_STATE=GUI_CPU_SINGLE_STEPPING;
nodelay(stdscr, FALSE);
}else{
CPU_STATE=RUNNING;
CPU_STATE=GUI_CPU_RUNNING;
nodelay(stdscr, TRUE);
}
}
break;
case 'q':
return 2;

2
gui.h
View File

@ -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 *);

12
main.c
View File

@ -25,6 +25,7 @@
#include <errno.h>
#include "assembly.h"
#include "cpu.h"
#include <unistd.h>
void help(char* progname){
printf("Usage: %s -i <file> \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,6 +177,7 @@ int main(int argc, char* argd[] ){
return 1;
}
if(simdata->cpu_state==CPU_RUNNING){
int ret;
if((ret=cpu_cycle_clock(simdata))){
cpu_simdata_free(simdata);
@ -190,6 +198,8 @@ int main(int argc, char* argd[] ){
}
return 1;
}
}else
usleep(100000);
}
if(end_gui()){

View File

@ -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;
}

View File

@ -1,6 +1,11 @@
#ifndef SIMDATA_HEADER
#include <stdint.h>
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

View File

@ -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