222 lines
7.8 KiB
C
222 lines
7.8 KiB
C
#include <stdio.h>
|
|
#include <inttypes.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "toy.h"
|
|
|
|
void print_instructionSet(void)
|
|
{
|
|
printf("interpretation terminated.\n");
|
|
printf("TOY-CPU Instruction Set:\n\n");
|
|
printf("OP_Code 0 (0000b):\t STORE<12 BIT ADDRESS>\n");
|
|
printf("OP_Code 1 (0001b):\t LOAD\t<12 BIT ADDRESS>\n");
|
|
printf("OP_Code 2 (0010b):\t JMPZ\t<12 BIT ADDRESS>\n");
|
|
printf("OP_Code 3 (0011b):\t ADD\t<12 BIT ADDRESS>\n");
|
|
printf("OP_Code 4 (0100b):\t SUB\t<12 BIT ADDRESS>\n");
|
|
printf("OP_Code 5 (0101b):\t OR\t<12 BIT ADDRESS>\n");
|
|
printf("OP_Code 6 (0110b):\t AND\t<12 BIT ADDRESS>\n");
|
|
printf("OP_Code 7 (0111b):\t XOR\t<12 BIT ADDRESS>\n");
|
|
printf("OP_Code 8 (1000b):\t NOT\t<12 BIT undefined>\n");
|
|
printf("OP_Code 9 (1001b):\t INC\t<12 BIT undefined>\n");
|
|
printf("OP_Code 10 (1010b):\t DEC\t<12 BIT undefined>\n");
|
|
printf("OP_Code 11 (1011b):\t ZERO\t<12 BIT undefined>\n");
|
|
printf("OP_Code 12 (1100b):\t NOP\t<12 BIT undefined>\n");
|
|
printf("OP_Code 13 (1101b):\t NOP\t<12 BIT undefined>\n");
|
|
printf("OP_Code 14 (1110b):\t NOP\t<12 BIT undefined>\n");
|
|
printf("OP_Code 15 (1111b):\t NOP\t<12 BIT undefined>\n\n");
|
|
|
|
printf("BIT\t|15 14 13 12|11 10 9 8 7 6 5 4 3 2 1 0|\n"
|
|
"\t---------------------------------------\n"
|
|
"\t| OP-CODE |\t\tADDRESS\t |\n"
|
|
"\t---------------------------------------\n\n");
|
|
printf("This machine has the following registers:\n"
|
|
"16 BIT Instruction Register(4 BIT OP, 12 BIT Addr)\n"
|
|
"16 BIT Accumulator\n"
|
|
"12 BIT Program Counter\n\n");
|
|
printf("Example: 0001000000001010 at RAM position 0\n"
|
|
"0001 means: LOAD the content of ADDRESS 000000001010 into the ACCU\n\n");
|
|
printf("This is an interpreter for the Koopman_TOY_CPU by\n"
|
|
"\tmichael.krause@uni-leipzig.de\n");
|
|
}
|
|
|
|
void print_architecture(void)
|
|
{
|
|
printf(
|
|
" +---------------+ +--------+\n"
|
|
" | | v |\n"
|
|
" +------------v------------+ | +--+-----+ |\n"
|
|
" | INSTRUCTION REGISTER(IR)| | |ACCU | |\n"
|
|
" +-------------------------+ | |(16 BIT)| |\n"
|
|
" ||OP-CODE || ADDRESS || | +--+-----+ |\n"
|
|
" ||(4 BIT) || (12 BIT) || | | |\n"
|
|
" |----+-----------+--------| | | |\n"
|
|
" +--- | --------- | -------+ +------+ | |\n"
|
|
" | | | v v |\n"
|
|
" +--------+ +--------+ | +-+--+ +--+-+ |\n"
|
|
" | | | | | +----+ | |\n"
|
|
" v | v | | ALU | |\n"
|
|
"+-----+-------+ | +----+--------+ | ++ (16 BIT) +-+ |\n"
|
|
"| | | | PC | | ++ ++ |\n"
|
|
"|CONTROL LOGIC| | | 12 BIT | | +-------+-+ |\n"
|
|
"| | | | | | | |\n"
|
|
"+-------------+ | +-+-----------+ | +-----------+\n"
|
|
" | | | v\n"
|
|
" v v | +------------+----------+\n"
|
|
" +-++ ++-+ | | DATA IN |\n"
|
|
" | +---+ | +-+ DATA OUT |\n"
|
|
" | MUX | | +-------------------+ |\n"
|
|
" ++ 12 BIT++ | |4k WORDS OF 16 BITS| |\n"
|
|
" +---+---+ | +-------------------+ |\n"
|
|
" | | |\n"
|
|
" +------------------ > ADDR |\n"
|
|
" +-----------------------+\n"
|
|
"\n");
|
|
}
|
|
|
|
void print_instruction(uint8_t opcode)
|
|
{
|
|
opcode%=16;
|
|
switch(opcode)
|
|
{
|
|
case 0: printf("STORE\n"); break;
|
|
case 1: printf("LOAD\n"); break;
|
|
case 2: printf("JMP\n"); break;
|
|
case 3: printf("ADD\n"); break;
|
|
case 4: printf("SUB\n"); break;
|
|
case 5: printf("OR\n"); break;
|
|
case 6: printf("AND\n"); break;
|
|
case 7: printf("XOR\n"); break;
|
|
case 8: printf("NOT\n"); break;
|
|
case 9: printf("INC\n"); break;
|
|
case 10: printf("DEC\n"); break;
|
|
case 11: printf("ZERO\n"); break;
|
|
case 12: printf("NOP\n"); break;
|
|
case 13: printf("NOP\n"); break;
|
|
case 14: printf("NOP\n"); break;
|
|
case 15: printf("NOP\n"); break;
|
|
}
|
|
}
|
|
|
|
int initialise_ram(uint16_t *ram, int argc, char **argv )
|
|
{
|
|
|
|
//opens and checks the input stream
|
|
FILE *fp;
|
|
int int_cache=0;
|
|
size_t j=0;
|
|
char tempS[CPU_WORD_SIZE+1]; //+1 for "\0
|
|
|
|
for(size_t i=0;i<RAM_SIZE;i++) ram[i]=0; //initialise the toy-RAM with NULL
|
|
|
|
if(argc<2)
|
|
{
|
|
fprintf(stderr,"%s","no \".toy\" input file!\n"
|
|
"interpretation terminated.\n\n"
|
|
"press toy-CPU -h for help\n"
|
|
"press toy-CPU -a for cpu architecture overview\n");
|
|
return -1;
|
|
}
|
|
if(argc >2)
|
|
{
|
|
fprintf(stderr,"%s","too many input files!\n");
|
|
return -1;
|
|
}
|
|
|
|
if(strcmp(argv[1],"-h")==0)
|
|
{
|
|
print_instructionSet();
|
|
return -1;
|
|
}
|
|
|
|
if(strcmp(argv[1],"-a")==0)
|
|
{
|
|
printf("interpretation terminated.\n\n");
|
|
print_architecture();
|
|
return -1;
|
|
}
|
|
|
|
if(NULL==(fp=fopen(argv[1],"r")))
|
|
{
|
|
fprintf(stderr,"%s","open input stream error !\n");
|
|
return -1;
|
|
}
|
|
|
|
// Fill the toy-RAM with data and break in case of error
|
|
for(;;)
|
|
{
|
|
for(int i = 0;i <= CPU_WORD_SIZE;i++)
|
|
{
|
|
int_cache = fgetc(fp);
|
|
|
|
if((int_cache =='\n' && i<CPU_WORD_SIZE) || (feof(fp) && i!=0))
|
|
{
|
|
fprintf(stderr,"%s","input file has word length error(s) !\n");
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
|
|
if(feof(fp)) break;
|
|
|
|
if((int_cache != '1' && int_cache != '0' && int_cache != '\n') || j >= RAM_SIZE )
|
|
{
|
|
fprintf(stderr,"%s","input file corrupted\n");
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
tempS[i] = int_cache;
|
|
}
|
|
if(feof(fp)) break;
|
|
tempS[CPU_WORD_SIZE] = '\0'; //replace \n with \0
|
|
ram[j] = strtoul(tempS,NULL,2);
|
|
j++;
|
|
}
|
|
fclose(fp);
|
|
return j;
|
|
}
|
|
|
|
uint8_t get_opcode(uint16_t instruction)
|
|
{
|
|
uint8_t opcode;
|
|
opcode = instruction>>12;
|
|
return opcode;
|
|
}
|
|
|
|
uint16_t get_data(uint16_t instruction)
|
|
{
|
|
uint16_t operand;
|
|
operand = instruction & 4095;
|
|
return operand;
|
|
}
|
|
|
|
static uint16_t accu;
|
|
const uint16_t * const ACCU = &accu;
|
|
|
|
bool execute(uint8_t op_code, int data_addr, uint16_t *ram) // jump if true
|
|
{
|
|
bool jump=false;
|
|
|
|
switch(op_code)
|
|
{
|
|
case 0: ram[data_addr] = accu; break; //STORE
|
|
case 1: accu = ram[data_addr]; break; //LOAD
|
|
case 2: jump = (accu == 0); break; //JMP
|
|
case 3: accu = accu + ram[data_addr]; break; //ADD
|
|
case 4: accu = accu - ram[data_addr]; break; //SUB
|
|
case 5: accu = accu | ram[data_addr]; break; //OR
|
|
case 6: accu = accu & ram[data_addr]; break; //AND
|
|
case 7: accu = accu ^ ram[data_addr]; break; //XOR
|
|
case 8: accu = ~accu; break; //NOT
|
|
case 9: accu++; break; //INC
|
|
case 10: accu--; break; //DEC
|
|
case 11: accu = 0; break; //ZERO
|
|
case 12: ; break; //NOP
|
|
case 13: ; break; //NOP
|
|
case 14: ; break; //NOP
|
|
case 15: ; break; //NOP
|
|
}
|
|
return jump;
|
|
}
|
|
|