22
22
//////////////////////////////////////////////////////////////////////////
31
#define MIN(a, b) (a > b ? b : a)
33
#define MEMORY_SIZE 65536
34
#define NUMBER_OF_REGISTERS 32
35
#define NUMBER_OF_COMMANDS 12
36
#define NUMBER_OF_INSTRUCTIONS 26
37
#define BUFFER_SIZE 300
38
#define BREAKPOINTS_ARRAY_SIZE 100
40
char debugInstructions[][NUMBER_OF_COMMANDS] = {"list","stp","reg","mem","search","pc", "run", "q","--help","break","back","reset"};
42
enum opCodes {HALT, ADD, ADDI, SUB,SUBI,MUL,MULI,LW,SW,BEQ, BNE, BLT, BGT, BLE,
43
BGE, JMP, JR, JAL, OUT, DIV, DIVI, MOD, MODI, FACT, FACTI,SWAP};
47
int32_t gpr[NUMBER_OF_REGISTERS];
48
uint8_t memory[MEMORY_SIZE];
51
//this is a global constant to store the state of the program, i.e. value 1 if program ran.
55
This method checks if the given tokenn is a register or not.
56
@param token : specifes the token to be checked
57
@return : returns 1 if the given token is a register
59
int checkRegister(char *token){
60
return (token!=NULL) ? (token[0]=='$') : 0;
64
This method returns an integer value for the given register
65
@param reg : specifes the reg whose int value has to be returned
66
@return : returns integer representation of the given string value
67
representation of the token
69
int getRegisterNumber(char *reg){
74
This method checks if a given string is a number.
75
@param num : points to the string to be checked
76
@return : returns 1 if true, 0 if false
79
int checkIfNumber(char *num) {
82
if (!isdigit(*temp)) return 0;
89
This method prints an "invalid command" error.
90
@param : takes no parameters
91
@return : no return value
93
void printInvalidCommandMessage(void) {
94
printf("Invalid command. Please enter --help for help\n");
98
This method checks if all strings in the given array of strings are registers.
99
@param regs : points to the array of strings to be checked
100
@return : returns 1 if all strings in the array are register names,
103
int checkAllRegistersAreValid(char **regs) {
105
if (!checkRegister(*regs) || !checkIfNumber(*regs+1) ||
106
getRegisterNumber(*regs) <0 ||
107
getRegisterNumber(*regs) >= NUMBER_OF_REGISTERS) {
116
This method returns the value stored in the specified register
117
@param reg : specifies the register index whose value has to be returned
118
@param proc : specifies the processor from which the value of register has to
120
@return : returns the value of the register specifed by the index given
122
int32_t getRegisterValue(struct Processor *proc, int8_t reg){
123
return proc->gpr[reg];
127
This method prints the registers according to the tokens received. The tokens
128
also contain print modifiers which specify any filters or parameters that the
129
print should satisfy, e.g. "-r" to print through the range of registers that
131
@param proc: specifies the processor from which the register values are to be
133
@param num : points to the array of tokens to be used during the printing
135
@return : no return value
137
void printReg(struct Processor *proc , char **tokens) {
139
int end = NUMBER_OF_REGISTERS-1;
141
if (strcmp("-r",tokens[0])==0) {
142
start = getRegisterNumber(tokens[1]);
143
end = getRegisterNumber(tokens[2]);
145
if(!start<end && !checkAllRegistersAreValid(tokens+1)){
146
printInvalidCommandMessage();
150
printInvalidCommandMessage();
154
else if (strcmp("-m",tokens[0])==0) {
156
if(!checkAllRegistersAreValid(tokens)){
157
printInvalidCommandMessage();
161
while(tokens[i]!=NULL) {
162
printf("%s = %i \t",tokens[i],getRegisterValue(proc, getRegisterNumber(tokens[i])));
164
if (i%8==0) printf(" \n");
169
else if (!strcmp("-a",tokens[0])==0){
170
printInvalidCommandMessage();
174
printf("%i,%i\n",x, end);
175
for (int i=0; i<end%8 ; i++) {
176
for (int j=0;j<8 ; j++) {
178
printf("$%i = %i \t",x,getRegisterValue(proc,x));
185
This method searches the registers for values specified in the tokens
186
received. The tokens also contain search modifiers which specify any filters
187
or parameters that the search should satisfy, e.g. "-r" to search through the
188
range of registers that follows.
189
@param proc : specifies the processor from which the register values are to
191
@param tokens : points to the array of tokens to be used during the printing
193
@return : no return value
195
void searchRegisters(struct Processor *proc, char **tokens) {
197
int end = NUMBER_OF_REGISTERS-1;
198
if (!checkIfNumber(tokens[1])) {
199
printInvalidCommandMessage();
202
int value = atoi(tokens[1]);
204
if (!checkAllRegistersAreValid(tokens+2)) {
205
printInvalidCommandMessage();
209
if (strcmp(tokens[0],"-r")==0) {
210
start = getRegisterNumber(tokens[2]);
211
end = getRegisterNumber(tokens[3]);
213
printInvalidCommandMessage();
216
if (tokens[4]!=NULL) {
217
printInvalidCommandMessage();
220
} else if (strcmp(tokens[0],"-a")!=0 || tokens[1]!=NULL) {
221
printInvalidCommandMessage();
226
for (int i = start; i<=end ; i++) {
227
if (proc->gpr[i]==value) {
228
printf("$%i=%i ",i,value);
235
This method checks if all strings in the given array of strings are names of
236
valid memory locations.
237
@param regs : points to the array of strings to be checked
238
@return : returns 1 if all strings in the array are memory locations,
241
int checkIfAllMemoryLocationsAreValid(char **tokens) {
243
if (!checkIfNumber(*tokens) || atoi(*tokens) <0
244
|| atoi(*tokens)>=MEMORY_SIZE) return 0;
250
This method returns the data stored in the memory of the specifed processor
251
at the specified address.
252
@param proc : specifies the processor
253
@param address : specifies the address of the memory which data has to be
255
@return : returns the value stored in the memory at the specified
258
uint32_t getMemory(struct Processor *proc, uint32_t address) {
259
return *(uint32_t *)(proc->memory + address);
263
This method prints the values memory locations according to the tokens
264
received. The tokens also contain print modifiers which specify any filters or
265
parameters that the print should satisfy, e.g. "-r" to print through the
266
range of memory locations that follows.
267
@param proc: specifies the processor from which the memory values are to be
269
@param num : points to the array of tokens to be used during the printing
271
@return : no return value
273
void printMemory(struct Processor *proc, char **tokens) {
275
int end = MEMORY_SIZE-1;
277
if ((strcmp(tokens[0],"-r"))==0) {
278
start = atoi(tokens[1]);
279
end = atoi(tokens[2]);
282
printInvalidCommandMessage();
285
if (tokens[4]!=NULL) {
286
printInvalidCommandMessage();
289
} else if ((strcmp(tokens[0],"-m"))==0) {
292
if (!checkIfAllMemoryLocationsAreValid(tokens+1)) {
293
printInvalidCommandMessage();
297
printf("M%i=%i ",atoi(*tokens),getMemory(proc,atoi(*tokens)));
300
if (j%8==0) printf("\n");
304
} else if ((strcmp(tokens[0],"-a"))!=0) {
305
printInvalidCommandMessage();
309
for (int c=0; x<end ; c++) {
310
for (int d=0;d<8&&x<=end ;d++) {
311
printf("M%i=%i \t",x,getMemory(proc,x));
320
This method breaks up a given string into tokens which seperate register
321
values, memory locations, search modifiers, etc
322
@param command: specifies the string to be tokenised
323
@return : returns an array of strings which can be used as tokens
325
char **tokeniseUserCommand(char *command) {
326
char *buff = malloc(sizeof(char) * BUFFER_SIZE);
327
buff = strncpy(buff,command,sizeof(char) *BUFFER_SIZE);
328
char **tokens = malloc(sizeof(char) *BUFFER_SIZE);
329
char *token = malloc(50);
331
token = strtok(buff," ");
335
token = strtok(NULL," ");
341
This method searches the memory locations for values specified in the tokens
342
received. The tokens also contain search modifiers which specify any filters
343
or parameters that the search should satisfy, e.g. "-r" to search through the
344
range of memory locations that follows.
345
@param proc : specifies the processor from which the memory values are to
347
@param tokens : points to the array of tokens to be used during the printing
349
@return : no return value
351
void searchMemory(struct Processor *proc, char **tokens) {
353
int end = MEMORY_SIZE-1;
354
if (!checkIfAllMemoryLocationsAreValid(tokens+1)) {
355
printInvalidCommandMessage();
358
int value = atoi(tokens[1]);
359
if (strcmp(tokens[0],"-r")==0) {
360
start = atoi(tokens[2]);
361
end = atoi(tokens[3]);
363
printInvalidCommandMessage();
366
if (tokens[4]!=NULL) {
367
printInvalidCommandMessage();
371
else if (strcmp(tokens[0],"-a")!=0) {
372
printInvalidCommandMessage();
377
for (int i = start; x<=end ; i++) {
378
if (proc->memory[i]==value) {
379
printf("M%i=%i\t",x,value);
390
This method begins the search process by checking if the tokens point towards
391
a memory location or a register and calling the required method.
392
@param proc : specifies the processor to be passed as one of the arguments
393
to the functions called
394
@param tokens : specifies the tokens to be used in the check
395
@return : no return value
397
void search(struct Processor *proc,char **tokens) {
398
if (strcmp(tokens[0],"-M") ==0) {
399
printf("mem search\n");
400
searchMemory(proc,tokens+1);
401
} else if (strcmp(tokens[0],"-R")==0) {
402
searchRegisters(proc,tokens+1);
407
This method uses an array of integest to check if the line number specified is
409
@param breakPoints : points to the integers that indicate the breakpoints
410
@param lineNumber : specifies the line number
411
@return : returns 1 if the line number is a break point, 0 if not
413
int checkIfBreakPoint(int *breakPoints, int lineNumber) {
414
for (int i=0; i<BREAKPOINTS_ARRAY_SIZE ;i++) {
415
if (breakPoints[i]==lineNumber) return 1;
416
if (breakPoints[i]==-1) return 0;
422
This method prints the current value of the program counter(PC).
423
@param proc : specifies the processor from which the PC value is to be
425
@return : no return value
427
void printPC( struct Processor *proc) {
428
printf("PC = %i \n",proc->pc);
434
This method returns the opcode (bit 0 to 5) from the given 32 bit instruction
435
@param instruction : This specifies the 32 bit instruction
436
@return : The method returns 8bit representation of the opcode
438
uint8_t getOpcode(uint32_t instruction) {
439
uint32_t mask = 0xfc000000;
440
uint32_t opcd = mask & instruction;
442
uint8_t opCode = (int) opcd;
447
This method returns the bit 6 to 31 of the given instruction, i.e. the address
448
for j-type instructions
449
@param instruction : this specifies the instruction
450
@return : the method returns 32 bit representation of the bit 6 to
451
31 of the given instruction
453
uint32_t getAddress(uint32_t instruction) {
454
uint32_t mask = 0x03ffffff;
455
return mask & instruction;
459
This method returns the bit 6 to 10 of the given instruction
460
@param instruction : this specifies the instruction
461
@return : the method returns 8 bit representation of the bit 6 to
462
10 of the given instruction
464
uint8_t getR1(uint32_t instruction){
465
uint32_t mask = 0x03e00000;
466
uint32_t reg = mask & instruction;
467
uint8_t r1 = reg>>21;
473
This method returns the bit 11 to 15 of the given instruction
474
@param instruction : this specifies the instruction
475
@return : the method returns 8 bit representation of the bit 11 to
476
15 of the given instruction
478
uint8_t getR2(uint32_t instruction) {
479
uint32_t mask = 0xf8000;
480
uint32_t reg = mask & instruction;
481
uint8_t r2 = reg >> 16;
486
This method returns the bit 16 to 21 of the given instruction
487
@param instruction : this specifies the instruction
488
@return : the method returns 8 bit representation of the bit 16 to
489
21 of the given instruction
491
uint8_t getR3(uint32_t instruction) {
492
uint32_t mask = 0x0007C00;
493
return ((mask & instruction) >> 11);
497
This method returns the bit 16 to 31 of the given instruction
498
@param instruction : this specifies the instruction
499
@return : the method returns 8 bit representation of the bit 16 to
500
31 of the given instruction
502
int16_t getImmediateValue(uint32_t instruction) {
503
uint32_t mask = 0x0000ffff;
504
return (int16_t)(mask & instruction);
508
This method sets the value of the memory at the specified addredd to the value
510
@param proc : specifies the processor
511
@param address : specifies the address of memory which needs the value to be
512
set to the given value
513
@param value : specifies the new value for the memory to be set
515
void setMemory(struct Processor *proc, uint32_t address, int32_t value) {
516
*(uint32_t *)(proc->memory + address) = value;
520
This method returns the instruction stored in the memory at address specified
521
by the program counter of the processor.
522
@param proc : specifies the processor which contains the program counter,
523
memory, and registers
525
uint32_t getInstructionAtPC(struct Processor *proc){
526
return *(uint32_t *)(proc->memory + proc->pc);
530
This method prints a segmentation fault error message.
531
@param : takes no parameters
532
@return : no return value
534
void printSegmentationFaultMessage(void) {
535
printf("Executing the current line would cause segmentation fault.\n");
536
printf("Please use the 'list' command to track the line where the error occurred\n");
540
This method checks if the given instruction is a valid R-type instruction.
541
@param ins : this specifies the instruction
544
int checkRtypeInstructionIsValid(uint32_t ins) {
545
uint8_t r1 = getR1(ins);
546
uint8_t r2 = getR2(ins);
547
uint8_t r3 = getR3(ins);
548
if (r1<0 || r2<0 || r3<0 || r1>=NUMBER_OF_REGISTERS || r2>=NUMBER_OF_REGISTERS
549
|| r3>=NUMBER_OF_REGISTERS) {
550
printSegmentationFaultMessage();
557
This method checks if the given instruction is a valid branch instruction.
558
@param ins : specifies the instruction to be used for the check
559
@param proc : specifies the processor which contains the values registers and
561
@return : returns 1 if the instruction is a valid branch instruction,
564
int checkBranchInstructionIsValid(uint32_t ins, struct Processor *proc) {
565
uint8_t r1 = getR1(ins);
566
uint8_t r2 = getR2(ins);
567
int16_t iVal = getImmediateValue(ins);
568
uint32_t pc = proc->pc;
569
if (r1<0 || r2<0 || r1>=NUMBER_OF_REGISTERS || r2>=NUMBER_OF_REGISTERS
570
|| pc+(iVal*4)<0 || pc+(iVal*4)>=MEMORY_SIZE) {
571
printSegmentationFaultMessage();
578
This method checks if the given instruction is a valid I-type instruction.
579
@param ins : specifies the instruction to be used for the check
580
@return : returns 1 if the instruction is a valid I-type instruction,
583
int checkItypeInstructionIsValid(uint32_t ins) {
584
uint8_t r1 = getR1(ins);
585
uint8_t r2 = getR2(ins);
586
if (r1<0 || r2<0 || r1>=NUMBER_OF_REGISTERS || r2>=NUMBER_OF_REGISTERS) {
587
printSegmentationFaultMessage();
594
This method checks if the given instruction is a valid J-type instruction.
595
@param ins : specifies the instruction to be used for the check
596
@return : returns 1 if the instruction is a valid J-type instruction,
599
int checkJtypeIsValid(uint32_t ins) {
600
uint32_t add = getAddress(ins);
601
if (add<0 || add>=MEMORY_SIZE) {
602
printSegmentationFaultMessage();
609
This method checks if the given instruction is a valid "load" or "store"
611
@param ins : specifies the instruction to be used for the check
612
@return : returns 1 if the "load"/"store" instruction is valid, 0 if not
614
int checkIfLoadAndStoreAreValid(uint32_t ins) {
615
uint8_t r1 = getR1(ins);
616
uint8_t r2 = getR2(ins);
617
int16_t iVal = getImmediateValue(ins);
618
if (r1<0 || r2<0 || r1>=NUMBER_OF_REGISTERS || r2>=NUMBER_OF_REGISTERS
619
|| r2+iVal<0 || r2+iVal>=MEMORY_SIZE) {
620
printSegmentationFaultMessage();
627
This method checks if the current intruction is valid.
628
@param processor : specifies the processor which contains the value of the
630
@return : returns 1 if the instruction at PC is a valid instruction,
633
int checkIfInstructionIsValid(struct Processor *processor) {
634
uint32_t instruction = getInstructionAtPC(processor);
635
uint8_t opcode = getOpcode(instruction);
636
if (opcode<0 || opcode>NUMBER_OF_INSTRUCTIONS) {
637
printf("The opcode for the current instruction is invalid. This would cause SEGMENTATION FAULT\n");
642
case HALT : return 1;
643
case ADD : return checkRtypeInstructionIsValid(instruction)!=0;
644
case ADDI :return checkItypeInstructionIsValid(instruction)!=0;
645
case SUB : return checkRtypeInstructionIsValid(instruction)!=0;
646
case SUBI : return checkItypeInstructionIsValid(instruction)!=0;
647
case MUL : return checkRtypeInstructionIsValid(instruction)!=0;
648
case MULI : return checkItypeInstructionIsValid(instruction)!=0;
649
case LW : return checkIfLoadAndStoreAreValid(instruction)!=0;
650
case SW : return checkIfLoadAndStoreAreValid(instruction)!=0;
651
case BEQ : return checkBranchInstructionIsValid(instruction,processor)!=0;
652
case BNE : return checkBranchInstructionIsValid(instruction,processor)!=0;
653
case BLT : return checkBranchInstructionIsValid(instruction,processor)!=0;
654
case BGT : return checkBranchInstructionIsValid(instruction,processor)!=0;
655
case BLE : return checkBranchInstructionIsValid(instruction,processor)!=0;
656
case BGE : return checkBranchInstructionIsValid(instruction,processor)!=0;
657
case JMP : return checkJtypeIsValid(instruction)!=0;
658
case JR : return checkRtypeInstructionIsValid(instruction)!=0;
659
case JAL : return checkJtypeIsValid(instruction)!=0;
660
case OUT : return checkRtypeInstructionIsValid(instruction)!=0;
661
case DIV : return checkRtypeInstructionIsValid(instruction)!=0;
662
case DIVI : return checkItypeInstructionIsValid(instruction)!=0;
663
case MOD : return checkRtypeInstructionIsValid(instruction)!=0;
664
case MODI : return checkItypeInstructionIsValid(instruction)!=0;
665
case FACT : return checkRtypeInstructionIsValid(instruction)!=0;
666
case FACTI: return checkItypeInstructionIsValid(instruction)!=0;
667
case SWAP : return checkRtypeInstructionIsValid(instruction)!=0;
672
This method carries out the instruction and returns the integer result of the
674
@param processor : specifies the processor from which the instruction,
675
register and program counter values are to be taken
676
@return : returns the integer that is the result of the operations
678
int carryOutInstruction(struct Processor *processor) {
679
uint32_t instruction = getInstructionAtPC(processor);
680
uint8_t opcode = getOpcode(instruction);
681
if (opcode<0 || opcode>NUMBER_OF_INSTRUCTIONS) {
682
printf("The opcode for the current instruction is invalid. This would cause SEGMENTATION FAULT\n");
686
uint32_t backupPC = processor->pc;
690
case HALT : return 0;
691
case ADD : if (checkRtypeInstructionIsValid(instruction)==0) return 0;
692
processor->gpr[getR1(instruction)] =
693
getRegisterValue(processor, getR2(instruction)) +
694
getRegisterValue(processor, getR3(instruction));
697
case ADDI : if (checkItypeInstructionIsValid(instruction)==0) return 0;
698
processor->gpr[getR1(instruction)] =
699
getRegisterValue(processor, getR2(instruction)) +
700
getImmediateValue(instruction);
703
case SUB : if (checkRtypeInstructionIsValid(instruction)==0) return 0;
704
processor->gpr[getR1(instruction)] =
705
getRegisterValue(processor, getR2(instruction)) -
706
getRegisterValue(processor, getR3(instruction));
709
case SUBI : if (checkItypeInstructionIsValid(instruction)==0) return 0;
710
processor->gpr[getR1(instruction)] =
711
getRegisterValue(processor, getR2(instruction)) -
712
getImmediateValue(instruction);
715
case MUL : if (checkRtypeInstructionIsValid(instruction)==0) return 0;
716
processor->gpr[getR1(instruction)] =
717
getRegisterValue(processor, getR2(instruction)) *
718
getRegisterValue(processor, getR3(instruction));
721
case MULI : if (checkItypeInstructionIsValid(instruction)==0) return 0;
722
processor->gpr[getR1(instruction)] =
723
getRegisterValue(processor, getR2(instruction)) *
724
getImmediateValue(instruction);
727
case LW : processor->gpr[getR1(instruction)] =
729
getRegisterValue(processor, getR2(instruction)) +
730
getImmediateValue(instruction));
733
case SW : setMemory(processor, getRegisterValue
734
(processor, getR2(instruction)) +
735
getImmediateValue(instruction),
736
getRegisterValue(processor, getR1(instruction)));
739
case BEQ : if (checkBranchInstructionIsValid(instruction,processor)==0)
741
if (processor->gpr[getR1(instruction)] ==
742
processor->gpr[getR2(instruction)])
743
{ processor->pc += getImmediateValue(instruction) * 4;};
746
case BNE : if (checkBranchInstructionIsValid(instruction,processor)==0)
748
if (processor->gpr[getR1(instruction)] !=
749
processor->gpr[getR2(instruction)])
750
{ processor->pc += getImmediateValue(instruction) * 4;};
753
case BLT : if (checkBranchInstructionIsValid(instruction,processor)==0)
755
if (processor->gpr[getR1(instruction)] <
756
processor->gpr[getR2(instruction)])
757
{ processor->pc += getImmediateValue(instruction) * 4;};
760
case BGT : if (checkBranchInstructionIsValid(instruction,processor)==0)
762
if (processor->gpr[getR1(instruction)] >
763
processor->gpr[getR2(instruction)])
764
{ processor->pc += getImmediateValue(instruction) * 4;};
767
case BLE : if (checkBranchInstructionIsValid(instruction,processor)==0)
769
if (processor->gpr[getR1(instruction)] <=
770
processor->gpr[getR2(instruction)])
771
{ processor->pc += getImmediateValue(instruction) * 4;};
774
case BGE : if (checkBranchInstructionIsValid(instruction,processor)==0)
776
if (processor->gpr[getR1(instruction)] >=
777
processor->gpr[getR2(instruction)])
778
{ processor->pc += (getImmediateValue(instruction) * 4);};
781
case JMP : if (checkJtypeIsValid(instruction)==0) return 0;
782
processor->pc = getAddress(instruction);
785
case JR : if (checkRtypeInstructionIsValid(instruction)==0) return 0;
786
processor->pc = getRegisterValue
787
(processor, getR1(instruction));
790
case JAL : if (checkJtypeIsValid(instruction)==0) return 0;
791
processor->gpr[31] = processor->pc + sizeof(uint32_t);
792
processor->pc = getAddress(instruction);
795
case OUT : if (checkRtypeInstructionIsValid(instruction)==0) return 0;
796
printf("%c", (char)getRegisterValue
797
(processor, getR1(instruction)));
800
case DIV : if (checkRtypeInstructionIsValid(instruction)==0) return 0;
801
division = div(getRegisterValue(processor,getR2(instruction))
802
,getRegisterValue(processor,getR3(instruction)));
803
processor->gpr[getR1(instruction)] = division.quot;
805
case DIVI : if (checkItypeInstructionIsValid(instruction)==0) return 0;
806
division = div(getRegisterValue(processor,getR2(instruction))
807
,getImmediateValue(instruction));
808
processor->gpr[getR1(instruction)] = division.quot;
810
case MOD : if (checkRtypeInstructionIsValid(instruction)==0) return 0;
811
division = div(getRegisterValue(processor,getR2(instruction))
812
,getRegisterValue(processor,getR3(instruction)));
813
processor->gpr[getR1(instruction)] = division.rem;
815
case MODI : if (checkItypeInstructionIsValid(instruction)==0) return 0;
816
division = div(getRegisterValue(processor,getR2(instruction))
817
,getImmediateValue(instruction));
818
processor->gpr[getR1(instruction)] = division.rem;
820
case FACT : if (checkRtypeInstructionIsValid(instruction)==0) return 0;
821
processor->gpr[getR1(instruction)] =
822
getRegisterValue(processor, getR2(instruction));
823
for(int i = 1; i<processor->gpr[getR2(instruction)] ; i++) {
824
processor->gpr[getR1(instruction)] =
825
(getRegisterValue(processor, getR1(instruction)))*
826
(getRegisterValue(processor, getR2(instruction))-i);
830
case FACTI: if (checkItypeInstructionIsValid(instruction)==0) return 0;
831
processor->gpr[getR1(instruction)] =
832
getImmediateValue(instruction);
833
for(int i = 1; i<getImmediateValue(instruction) ; i++) {
834
processor->gpr[getR1(instruction)] =
835
(getRegisterValue(processor, getR1(instruction)))*
836
(getImmediateValue(instruction)-i);
840
case SWAP : if (checkRtypeInstructionIsValid(instruction)==0) return 0;
842
getRegisterValue(processor, getR1(instruction));
843
processor->gpr[getR1(instruction)] =
844
getRegisterValue(processor, getR2(instruction));
845
processor->gpr[getR2(instruction)] = temp;
848
if(processor->pc == backupPC) processor->pc += sizeof(uint32_t);
852
/*this method carries out one step
853
@param : current state of the processor
854
@return : a string without the white spaces in it
856
void step(struct Processor *proc) {
857
if (programExitValue==1) {
858
printf("No programs running currently. The previous program has exited already so step cannot be executed\n");
861
int retVal = carryOutInstruction(proc);
864
printf("\n\nProgram exited normally.\n");
867
/*This method removes the space in a string
868
@param str : a string which has white space in it
869
@return : a string without the white spaces in it
871
char *removeSpace(char *str) {
873
if (isspace((int) *str)==0) return str;
880
The method binaryFileLoader loads the binary file in the memory of the given
882
@param processor : this specifes the current processor with the memory to be
883
initialised with the given instructions from given filepath
884
@param filepath : this specifies the path of the file which contains the
885
instructions to be loaded in the memory.
887
void binaryFileLoader(char *filepath, struct Processor *processor) {
889
fp = fopen(filepath,"rb");
891
perror("ERROR in opening file");
897
fseek (fp , 0 , SEEK_END);
898
fileSize = ftell (fp);
901
fileSize = MIN(65536, fileSize);
903
fread(processor->memory, sizeof(uint32_t), fileSize, fp);
906
/* this method is used to get the specific line from the input file
907
@param filepath : the path to the file to be searched
908
@param n : the line number to be retrieved
909
@return : returns no specific value however prints out the line if it
910
exist or prints End of file reached before line
913
void listInstruction(char *filepath, int n) {
915
fp = fopen(filepath,"r");
916
char *buffer = (char *) malloc(BUFFER_SIZE * sizeof(char));
918
perror("ERROR in opening file");
921
while (!feof(fp) &&0<n ){
922
memset(buffer, 0, ((sizeof(char))*BUFFER_SIZE));
923
fgets (buffer, BUFFER_SIZE, fp);
924
if(strlen(buffer)>1) n--;
925
//printf("%s------n=%i----length =%i\n", buffer,n,strlen(buffer));
929
printf("%s", removeSpace(buffer));
932
perror("End of file reached before line");
941
This method prints the state of the processor at the end of execution of the
942
program; i.e. the data stored in all the registers and the value of program
943
counter at the end of the program
944
@param proc : this specifies the processor whose state has to be printed
946
void dumpProcessor(struct Processor *proc) {
947
fprintf(stderr, "\n\n-----\n\nPC=%d\n", proc->pc);
948
for(int i = 0; i < 4; i++) {
949
for(int j = 0; j < 8; j++) {
951
fprintf(stderr, "R%d=%d\t", reg, getRegisterValue(proc, reg));
953
fprintf(stderr, "\n");
957
This method prints out the Welcome message at the at the start of the
959
@param :Takes no parameters
960
@return :Returns no values
962
void printWelcomeMessage(void){
964
fp = fopen("welcomeMessage.txt","r");
965
char *buffer = (char *) malloc(BUFFER_SIZE * sizeof(char));
967
perror("ERROR in opening file");
971
memset(buffer, 0, ((sizeof(char))*BUFFER_SIZE));
972
fgets (buffer, BUFFER_SIZE, fp);
977
This method checks whether the user has inputted the right commands for
979
@param command: specifies the command to be used in the check
980
@return : returns 1 if the command is valid and 0 if not
982
int checkUserCommandIsValid(char *command) {
983
for (int i=0; i<NUMBER_OF_COMMANDS; i++) {
984
if (strcmp(command,debugInstructions[i])==0) return 1;
989
This is a method to get a command from the user. Endlessly loops to
990
continuously get commands from the user until program is quit.
991
@param : Takes no parameters
992
@return : Returns an array of strings that the user types into the debugger
993
that seem like valid commands
995
char **getUserCommand(void) {
997
char *buff = malloc(BUFFER_SIZE);
998
fgets(buff,BUFFER_SIZE,stdin);
999
char *ptr = malloc(2);
1000
if( (ptr = strchr(buff, '\n')) != NULL) *ptr = '\0';
1001
char **tokens = malloc(sizeof(char) * BUFFER_SIZE);
1002
tokens = tokeniseUserCommand(buff);
1003
if (checkUserCommandIsValid(tokens[0])) return tokens;
1004
printInvalidCommandMessage();
1005
return getUserCommand();
1009
This is a method to get confirmation from the user of quitting the
1011
@param :Takes no parameters
1012
@return :returns 1 if the user wants to quit or 0 otherwise
1014
int confirmToQuit(void) {
1015
printf("Are you sure you want to quit? enter y for yes and n for no\n(JVG)");
1016
char *ans = malloc(sizeof(char) * BUFFER_SIZE);
1017
fgets(ans,sizeof(char) * BUFFER_SIZE, stdin);
1019
if( (ptr = strchr(ans, '\n')) != NULL) *ptr = '\0';
1020
int ret = strcmp(ans,"y")==0;
1021
if (ret==0 && strcmp(ans,"n")!=0) {
1023
printf("Please enter a valid answer\n");
1024
return confirmToQuit();
1031
Runs the piece of code from the current step.
1032
@param proc : specifies the processor containing the PC values
1033
@param breakPoints : specifies the break points to be checked for in the lines
1035
@return : no return value.
1037
void run(struct Processor *proc,int *breakPoints) {
1038
if (programExitValue==1) {
1039
printf("No programs running currently. The previous program has exited already so step cannot be executed\n");
1045
retVal = carryOutInstruction(proc);
1046
} while (retVal && !checkIfBreakPoint(breakPoints,(proc->pc/4)+1));
1047
if (programExitValue==1) return;
1048
if (checkIfBreakPoint(breakPoints,((int) proc->pc/4)+1)==1) {
1049
printf("Breakpoint reached.\n");
1053
dumpProcessor(proc);
1054
programExitValue = 1;
1055
printf("\nProgram exited normally.\n");
1059
This method sets a breakpoint at every occurance of a breakpoint in the given
1061
@param breakPoints : specifies the line numbers to be used as break points
1062
@param tokens : specifies the array of strings to be used as the tokens
1063
that need to be checked for numbers
1064
@return : no return value
1066
void setBreakPoints(int *breakPoints,char **tokens) {
1068
if (strcmp(tokens[0],"-r")==0) {
1071
if (checkIfNumber(*tokens)==0) {
1072
printInvalidCommandMessage();
1075
if (breakPoints[i]==atoi(*tokens)) {
1076
breakPoints[i] = -1;
1078
if (breakPoints[i] ==-1) {
1079
printInvalidCommandMessage();
1080
printf("breakpoint does not exists");
1086
} else if (strcmp(tokens[0],"-a")==0) {
1088
int *temp = malloc(sizeof(int) * BREAKPOINTS_ARRAY_SIZE);
1090
if (checkIfNumber(*tokens)==0) {
1091
printInvalidCommandMessage();
1094
temp[i] = atoi(*tokens);
1098
memcpy(breakPoints,temp,sizeof(int) * i);
1104
This method is used to reset the state of the cpu to the state it would
1105
have been in at the start of the program.
1106
@param proc :specifes the current state of the cpu
1107
@param bin :specifies the filepath of the binary path
1109
void reset(struct Processor *proc,char *bin) {
1110
memset(proc,0,sizeof(struct Processor));
1111
binaryFileLoader(bin,proc);
1112
programExitValue = 0;
1116
This method displays the help content in the terminal for the user to get help
1117
@param tokens : specifies the tokens of the given command for help
1119
void help(char **tokens){
1120
if(tokens[1]!=NULL){
1121
if(strcmp(tokens[1],"mem") ==0){
1122
system("cat help/mem.txt");
1125
else if(strcmp(tokens[1],"reg") ==0){
1126
system("cat help/reg.txt");
1129
else if(strcmp(tokens[1],"search") ==0){
1130
system("cat help/search.txt");
1134
system("cat help/help.txt");
1138
This method is used to execute the user command.
1139
@param assembly : specifies the assembly instruction to be used
1140
@param bin : specifies the binary code to be used
1141
@param proc : specifies the processor that contains the values used
1142
@param tokens : specifies the tokens to be used to execute the command
1143
@param breakPoints : specifies the various line numbers to be used as break
1145
@return : returns 0 when executing any command except confirmation
1148
int executeUserCommand(char *assembly, char *bin, struct Processor *proc,
1149
char **tokens, int *breakPoints) {
1150
if (strcmp(tokens[0], "reg")==0) {
1152
printReg(proc, tokens);
1154
} else if (strcmp(tokens[0], "mem")==0) {
1156
printMemory(proc, tokens);
1158
} else if (strcmp(tokens[0], "pc")==0) {
1161
} else if (strcmp(tokens[0], "search")==0) {
1163
search(proc, tokens);
1165
} else if (strcmp(tokens[0], "stp")==0) {
1168
} else if (strcmp(tokens[0], "list")==0) {
1169
listInstruction(assembly, ((proc->pc)/4)+1);
1171
} else if (strcmp(tokens[0], "--help")==0) {
1174
} else if (strcmp(tokens[0], "run")==0) {
1175
run(proc,breakPoints);
1177
} else if (strcmp(tokens[0],"q")==0) {
1178
return confirmToQuit();
1179
} else if (strcmp(tokens[0],"break")==0) {
1180
setBreakPoints(breakPoints,tokens+1);
1182
} else if(strcmp(tokens[0],"reset")==0) {
1189
int main(int argc, char **argv) {
1190
struct Processor *proc = malloc(sizeof(struct Processor));
1191
assert("There are wrong number of arguents given" && argc==3);
1192
char *fBin = argv[2];
1193
char *fAssembly = argv[1];
1194
memset(proc,0,sizeof(struct Processor));
1195
binaryFileLoader(fBin,proc);
1197
int *breakPoints = malloc(sizeof(int) *BREAKPOINTS_ARRAY_SIZE);
1198
memset(breakPoints,-1,sizeof(int) *BREAKPOINTS_ARRAY_SIZE);
1199
printWelcomeMessage();
1200
char **tokens = malloc(sizeof(char) *BUFFER_SIZE);
1203
tokens = getUserCommand();
1204
returnVal = executeUserCommand(fAssembly,fBin,proc,tokens,breakPoints);
1206
} while (!returnVal);
1207
printf("Thanks for using JVG debugger\n");
1211
return EXIT_SUCCESS;
24
//////////////////////////////////////////////////////////////////////////
26
// Generation of boundary representation from arbitrary geophysical
27
// fields and initialisation for anisotropic, unstructured meshing.
29
// Copyright (C) 2011-2013 Dr Adam S. Candy, adam.candy@imperial.ac.uk
31
// This program is free software: you can redistribute it and/or modify
32
// it under the terms of the GNU General Public License as published by
33
// the Free Software Foundation, either version 3 of the License, or
34
// (at your option) any later version.
36
// This program is distributed in the hope that it will be useful,
37
// but WITHOUT ANY WARRANTY; without even the implied warranty of
38
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
39
// GNU General Public License for more details.
41
// You should have received a copy of the GNU General Public License
42
// along with this program. If not, see <http://www.gnu.org/licenses/>.
44
//////////////////////////////////////////////////////////////////////////