МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИНАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ «ЛЬВІВСЬКА ПОЛІТЕХНІКА»
ІНСТИТУТ КОМП’ЮТЕРНОЇ ТЕХНІКИ АВТОМАТИКИ ТА МЕТРОЛОГІЇ
ЗВІТ ЛАБОРАТОРНОЇ РОБОТИ №4
З ПРЕДМЕТУ: «Архітектура комп’ютерів»
ТЕМА: «Робота з симулятором машини Ноймана. Дослідження архітектури
системи команд»
Львів – 2012
Мета роботи: зрозуміти принципи виконання архітектури системи команд на симуляторі машини Ноймана, зрозуміти і дослідити виконання інструкції.
Завдання: розширити архітектуру систему команд симулятора машини Ноймана, скласти програму на асемблері з розшириним набором команд, перетворити її у машинні коди, запустити симулятор, увести до нього коди машинних, проаналізувати і пояснити отримані результати, довести коректність роботи розширеного набору команд, скласти звіт з виконання лабораторних досліджень та захистити його.
Хід роботи:
Варіант 18
Побітове логічне І
Лістинг програм:
asol.c
/* Assembler for LC */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAXLINELENGTH 1000
#define MAXNUMLABELS 65536
#define MAXLABELLENGTH 7 /* includes the null character termination */
#define ADD 0
#define NAND 1
#define LW 2
#define SW 3
#define BEQ 4
#define JALR 5
#define HALT 6
#define AND 7
int readAndParse(FILE *, char *, char *, char *, char *, char *);
int translateSymbol(char labelArray[MAXNUMLABELS][MAXLABELLENGTH], int labelAddress[MAXNUMLABELS], int, char *);
int isNumber(char *);
void testRegArg(char *);
void testAddrArg(char *);
int
main(int argc, char *argv[])
{
char *inFileString, *outFileString;
FILE *inFilePtr, *outFilePtr;
int address;
char label[MAXLINELENGTH], opcode[MAXLINELENGTH], arg0[MAXLINELENGTH],
arg1[MAXLINELENGTH], arg2[MAXLINELENGTH], argTmp[MAXLINELENGTH];
int i;
int numLabels=0;
int num;
int addressField;
char labelArray[MAXNUMLABELS][MAXLABELLENGTH];
int labelAddress[MAXNUMLABELS];
if (argc != 3) {
printf("error: usage: %s <assembly-code-file> <machine-code-file>\n",
argv[0]);
exit(1);
}
inFileString = argv[1];
outFileString = argv[2];
inFilePtr = fopen(inFileString, "r");
if (inFilePtr == NULL) {
printf("error in opening %s\n", inFileString);
exit(1);
}
outFilePtr = fopen(outFileString, "w");
if (outFilePtr == NULL) {
printf("error in opening %s\n", outFileString);
exit(1);
}
/* map symbols to addresses */
/* assume address start at 0 */
for (address=0; readAndParse(inFilePtr, label, opcode, arg0, arg1, arg2);
address++) {
/*
printf("%d: label=%s, opcode=%s, arg0=%s, arg1=%s, arg2=%s\n",
address, label, opcode, arg0, arg1, arg2);
*/
/* check for illegal opcode */
if (strcmp(opcode, "add") && strcmp(opcode, "nand") &&
strcmp(opcode, "lw") && strcmp(opcode, "sw") &&
strcmp(opcode, "beq") && strcmp(opcode, "jalr") &&
strcmp(opcode, "halt") && strcmp(opcode, "and") &&
strcmp(opcode, ".fill") ) {
printf("error: unrecognized opcode %s at address %d\n", opcode,
address);
exit(1);
}
/* check register fields */
if (!strcmp(opcode, "add") || !strcmp(opcode, "nand") ||
!strcmp(opcode, "lw") || !strcmp(opcode, "sw") ||
!strcmp(opcode, "and") ||
!strcmp(opcode, "beq") || !strcmp(opcode, "jalr")) {
testRegArg(arg0);
testRegArg(arg1);
}
if (!strcmp(opcode, "add") || !strcmp(opcode, "nand") || !strcmp(opcode, "and") ) {
testRegArg(arg2);
}
/* check addressField */
if (!strcmp(opcode, "lw") || !strcmp(opcode, "sw") ||
!strcmp(opcode, "beq")) {
testAddrArg(arg2);
}
if (!strcmp(opcode, ".fill")) {
testAddrArg(arg0);
}
/* check for enough arguments */
if ( (strcmp(opcode, "halt") && strcmp(opcode, "and") &&
strcmp(opcode, ".fill") && strcmp(opcode, "jalr")
&& arg2[0]=='\0') ||
(!strcmp(opcode, "jalr") && arg1[0]=='\0') ||
(!strcmp(opcode, ".fill") && arg0[0]=='\0')) {
printf("error at address %d: not enough arguments\n", address);
exit(2);
}
if (label[0] != '\0') {
/* check for labels that are too long */
if (strlen(label) >= MAXLABELLENGTH) {
printf("label too long\n");
exit(2);
}
/* make sure label starts with letter */
if (! sscanf(label, "%[a-zA-Z]", argTmp) ) {
printf("label doesn't start with letter\n");
exit(2);
}
/* make sure label consists of only letters and numbers */
sscanf(label, "%[a-zA-Z0-9]", argTmp);
if (strcmp(argTmp, label)) {
printf("label has character other than letters and numbers\n");
exit(2);
}
/* look for duplicate label */
for (i=0; i<numLabels; i++) {
if (!strcmp(label, labelArray[i])) {
printf("error: duplicate label %s at address %d\n",
label, address);
exit(1);
}
}
/* see if there are too many labels */
if (numLabels >= MAXNUMLABELS) {
printf("error: too many labels (label=%s)\n", label);
exit(2);
}
strcpy(labelArray[numLabels], label);
labelAddress[numLabels++] = address;
}
}
for (i=0; i<numLabels; i++) {
/* printf("%s = %d\n", labelArray[i], labelAddress[i]); */
}
/* now do second pass (print machine code, with symbols filled in as
addresses) */
rewind(inFilePtr);
for (address=0; readAndParse(inFilePtr, label, opcode, arg0, arg1, arg2);
address++) {
if (!strcmp(opcode, "add")) {
num = (ADD << 22) | (atoi(arg0) << 19) | (atoi(arg1) << 16)
| atoi(arg2);
} else if (!strcmp(opcode, "nand")) {
num = (NAND << 22) | (atoi(arg0) << 19) | (atoi(arg1) << 16)
| atoi(arg2);
} else if (!strcmp(opcode, "jalr")) {
num = (JALR << 22) | (atoi(arg0) << 19) | (atoi(arg1) << 16);
} else if (!strcmp(opcode, "halt")) {
num = (HALT << 22);
} else if (!strcmp(opcode, "and")) {
num = (AND << 22) | (atoi(arg0) << 19) | (atoi(arg1) << 16)
| atoi(arg2);
} else if (!strcmp(opcode, "lw") || !strcmp(opcode, "sw") ||
!strcmp(opcode, "beq")) {
/* if arg2 is symbolic, then translate into an address */
if (!isNumber(arg2)) {
addressField = translateSymbol(labelArray, labelAddress,
numLabels, arg2);
/*
printf("%s being translated into %d\n", arg2, addressField);
*/
if (!strcmp(opcode, "beq")) {
addressField = addressField-address-1;
}
} else {
addressField = atoi(arg2);
}
if (addressField < -32768 || addressField > 32767) {
printf("error: offset %d out of range\n", addressField);
exit(1);
}
/* truncate the offset field, in case it's negative */
addressField = addressField & 0xFFFF;
if (!strcmp(opcode, "beq")) {
num = (BEQ << 22) | (atoi(arg0) << 19) | (atoi(arg1) << 16)
| addressField;
} else {
/* lw or sw */
if (!strcmp(opcode, "lw")) {
num = (LW << 22) | (atoi(arg0) << 19) |
(atoi(arg1) << 16) | addressField;
} else {
num = (SW << 22) | (atoi(arg0) << 19) |
(atoi(arg1) << 16) | addressField;
}
}
} else if (!strcmp(opcode, ".fill")) {
if (!isNumber(arg0)) {
num = translateSymbol(labelArray, labelAddress, numLabels,
arg0);
} else {
num = atoi(arg0);
}
}
/* printf("(address %d): %d (hex 0x%x)\n", address, num, num); */
fprintf(outFilePtr, "%d\n", num);
}
exit(0);
}
/*
* Read and parse a line of the assembly-language file. Fields are returned
* in label, opcode, arg0, arg1, arg2 (these strings must have memory already
* allocated to them).
*
* Return values:
* 0 if reached end of file
* 1 if all went well
*
* exit(1) if line is too long.
*/
int
readAndParse(FILE *inFilePtr, char *label, char *opcode, char *arg0,
char *arg1, char *arg2)
{
char line[MAXLINELENGTH];
char *ptr = line;
/* delete prior values */
label[0] = opcode[0] = arg0[0] = arg1[0] = arg2[0] = '\0';
/* read the line from the assembly-language file */
if (fgets(line, MAXLINELENGTH, inFilePtr) == NULL) {
/* reached end of file */
return(0);
}
/* check for line too long */
if (strlen(line) == MAXLINELENGTH-1) {
printf("error: line too long\n");
exit(1);
}
/* is there a label? */
ptr = line;
if (sscanf(ptr, "%[^\t\n ]", label)) {
/* successfully read label; advance pointer over the label */
ptr += strlen(label);
}
/*
* Parse the rest of the line. Would be nice to have real regular
* expressions, but scanf will suffice.
*/
sscanf(ptr, "%*[\t\n\r ]%[^\t\n\r ]%*[\t\n\r ]%[^\t\n\r ]%*[\t\n\r ]%[^\t\n\r ]%*[\t\n\r ]%[^\t\n\r ]",
opcode, arg0, arg1, arg2);
return(1);
}
int
translateSymbol(char labelArray[MAXNUMLABELS][MAXLABELLENGTH],
int labelAddress[MAXNUMLABELS], int numLabels, char *symbol)
{
int i;
/* search through address label table */
for (i=0; i<numLabels && strcmp(symbol, labelArray[i]); i++) {
}
if (i>=numLabels) {
printf("error: missing label %s\n", symbol);
exit(1);
}
return(labelAddress[i]);
}
int
isNumber(char *string)
{
/* return 1 if string is a number */
int i;
return( (sscanf(string, "%d", &i)) == 1);
}
/*
* Test register argument; make sure it's in range and has no bad characters.
*/
void
testRegArg(char *arg)
{
int num;
char c;
if (atoi(arg) < 0 || atoi(arg) > 7) {
printf("error: register out of range\n");
exit(2);
}
if (sscanf(arg, "%d%c", &num, &c) != 1) {
printf("bad character in register argument\n");
exit(2);
}
}
/*
* Test addressField argument.
*/
void
testAddrArg(char *arg)
{
int num;
char c;
/* test numeric addressField */
if (isNumber(arg)) {
if (sscanf(arg, "%d%c", &num, &c) != 1) {
printf("bad character in addressField\n");
exit(2);
}
}
}
ssol.c
/*
* Instruction-level simulator for the LC
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUMMEMORY 65536 /* maximum number of words in memory */
#define NUMREGS 8 /* number of machine registers */
#define MAXLINELENGTH 1000
#define ADD 0
#define NAND 1
#define LW 2
#define SW 3
#define BEQ 4
#define JALR 5
#define HALT 6
#define AND 7
typedef struct stateStruct {
int pc;
int mem[NUMMEMORY];
int reg[NUMREGS];
int numMemory;
} stateType;
void printState(stateType *);
void run(stateType);
int convertNum(int);
int
main(int argc, char *argv[])
{
int i;
char line[MAXLINELENGTH];
stateType state;
FILE *filePtr;
if (argc != 2) {
printf("error: usage: %s <machine-code file>\n", argv[0]);
exit(1);
}
/* initialize memories and registers */
for (i=0; i<NUMMEMORY; i++) {
state.mem[i] = 0;
}
for (i=0; i<NUMREGS; i++) {
state.reg[i] = 0;
}
state.pc=0;
/* read machine-code file into instruction/data memory (starting at
address 0) */
filePtr = fopen(argv[1], "r");
if (filePtr == NULL) {
printf("error: can't open file %s\n", argv[1]);
perror("fopen");
exit(1);
}
for (state.numMemory=0; fgets(line, MAXLINELENGTH, filePtr) != NULL;
state.numMemory++) {
if (state.numMemory >= NUMMEMORY) {
printf("exceeded memory size\n");
exit(1);
}
if (sscanf(line, "%d", state.mem+state.numMemory) != 1) {
printf("error in reading address %d\n", state.numMemory);
exit(1);
}
printf("memory[%d]=%d\n", state.numMemory, state.mem[state.numMemory]);
}
printf("\n");
/* run never returns */
run(state);
return(0);
}
void
run(stateType state)
{
int arg0, arg1, arg2, addressField;
int instructions=0;
int opcode;
int maxMem=-1; /* highest memory address touched during run */
for (; 1; instructions++) { /* infinite loop, exits when it executes halt */
printState(&state);
if (state.pc < 0 || state.pc >= NUMMEMORY) {
printf("pc went out of the memory range\n");
exit(1);
}
maxMem = (state.pc > maxMem)?state.pc:maxMem;
/* this is to make the following code easier to read */
opcode = state.mem[state.pc] >> 22;
arg0 = (state.mem[state.pc] >> 19) & 0x7;
arg1 = (state.mem[state.pc] >> 16) & 0x7;
arg2 = state.mem[state.pc] & 0x7; /* only for add, nand */
addressField = convertNum(state.mem[state.pc] & 0xFFFF); /* for beq,
lw, sw */
state.pc++;
if (opcode == ADD) {
state.reg[arg2] = state.reg[arg0] + state.reg[arg1];
} else if (opcode == NAND) {
state.reg[arg2] = ~(state.reg[arg0] & state.reg[arg1]);
} else if (opcode == LW) {
if (state.reg[arg0] + addressField < 0 ||
state.reg[arg0] + addressField >= NUMMEMORY) {
printf("address out of bounds\n");
exit(1);
}
state.reg[arg1] = state.mem[state.reg[arg0] + addressField];
if (state.reg[arg0] + addressField > maxMem) {
maxMem = state.reg[arg0] + addressField;
}
} else if (opcode == SW) {
if (state.reg[arg0] + addressField < 0 ||
state.reg[arg0] + addressField >= NUMMEMORY) {
printf("address out of bounds\n");
exit(1);
}
state.mem[state.reg[arg0] + addressField] = state.reg[arg1];
if (state.reg[arg0] + addressField > maxMem) {
maxMem = state.reg[arg0] + addressField;
}
} else if (opcode == BEQ) {
if (state.reg[arg0] == state.reg[arg1]) {
state.pc += addressField;
}
} else if (opcode == JALR) {
state.reg[arg1] = state.pc;
if(arg0 != 0)
state.pc = state.reg[arg0];
else
state.pc = 0;
}
////////////////////////////////////////////
else if (opcode == AND) {
state.reg[arg2] = (state.reg[arg0] & state.reg[arg1]);
}
////////////////////////////////////////////
else if (opcode == HALT) {
printf("machine halted\n");
printf("total of %d instructions executed\n", instructions+1);
printf("final state of machine:\n");
printState(&state);
exit(0);
} else {
printf("error: illegal opcode 0x%x\n", opcode);
exit(1);
}
state.reg[0] = 0;
}
}
void
printState(stateType *statePtr)
{
int i;
printf("\n@@@\nstate:\n");
printf("\tpc %d\n", statePtr->pc);
printf("\tmemory:\n");
for (i=0; i<statePtr->numMemory; i++) {
printf("\t\tmem[ %d ] %d\n", i, statePtr->mem[i]);
}
printf("\tregisters:\n");
for (i=0; i<NUMREGS; i++) {
printf("\t\treg[ %d ] %d\n", i, statePtr->reg[i]);
}
printf("end state\n");
}
int
convertNum(int num)
{
/* convert a 16-bit number into a 32-bit Sun integer */
if (num & (1<<15) ) {
num -= (1<<16);
}
return(num);
}
Зміст файлу 1.as:
start lw 0 1 var1
lw 0 2 var2
and 1 2 3
halt
var1 .fill 6
var2 .fill 3
stAddr .fill start
Зміст файлу 1.mc:
8454148
8519685
30015491
25165824
6
3
2
Файл report.txt
memory[0]=8454148
memory[1]=8519685
memory[2]=30015491
memory[3]=25165824
memory[4]=6
memory[5]=3
memory[6]=2
@@@
state:
pc 0
memory:
mem[ 0 ] 8454148
mem[ 1 ] 8519685
mem[ 2 ] 30015491
mem[ 3 ] 25165824
mem[ 4 ] 6
mem[ 5 ] 3
mem[ 6 ] 2
registers:
reg[ 0 ] 0
reg[ 1 ] 0
reg[ 2 ] 0
reg[ 3 ] 0
reg[ 4 ] 0
reg[ 5 ] 0
reg[ 6 ] 0
reg[ 7 ] 0
end state
@@@
state:
pc 1
memory:
mem[ 0 ] 8454148
mem[ 1 ] 8519685
mem[ 2 ] 30015491
mem[ 3 ] 25165824
mem[ 4 ] 6
mem[ 5 ] 3
mem[ 6 ] 2
registers:
reg[ 0 ] 0
reg[ 1 ] 6
reg[ 2 ] 0
reg[ 3 ] 0
reg[ 4 ] 0
reg[ 5 ] 0
reg[ 6 ] 0
reg[ 7 ] 0
end state
@@@
state:
pc 2
memory:
mem[ 0 ] 8454148
mem[ 1 ] 8519685
mem[ 2 ] 30015491
mem[ 3 ] 25165824
mem[ 4 ] 6
mem[ 5 ] 3
mem[ 6 ] 2
registers:
reg[ 0 ] 0
reg[ 1 ] 6
reg[ 2 ] 3
reg[ 3 ] 0
reg[ 4 ] 0
reg[ 5 ] 0
reg[ 6 ] 0
reg[ 7 ] 0
end state
@@@
state:
pc 3
memory:
mem[ 0 ] 8454148
mem[ 1 ] 8519685
mem[ 2 ] 30015491
mem[ 3 ] 25165824
mem[ 4 ] 6
mem[ 5 ] 3
mem[ 6 ] 2
registers:
reg[ 0 ] 0
reg[ 1 ] 6
reg[ 2 ] 3
reg[ 3 ] 2
reg[ 4 ] 0
reg[ 5 ] 0
reg[ 6 ] 0
reg[ 7 ] 0
end state
machine halted
total of 4 instructions executed
final state of machine:
@@@
state:
pc 4
memory:
mem[ 0 ] 8454148
mem[ 1 ] 8519685
mem[ 2 ] 30015491
mem[ 3 ] 25165824
mem[ 4 ] 6
mem[ 5 ] 3
mem[ 6 ] 2
registers:
reg[ 0 ] 0
reg[ 1 ] 6
reg[ 2 ] 3
reg[ 3 ] 2
reg[ 4 ] 0
reg[ 5 ] 0
reg[ 6 ] 0
reg[ 7 ] 0
end state
Висновок: виконавши дану лабораторну роботу, я зрозуміла принципи виконання архітектури системи команд на симуляторі машини Ноймана, зрозуміла і дослідила виконання інструкції.