4.1 Introduction
Fish is “programmable invertebrate”: In fish, rather than supplying control signals and clock edges every time by a human hand, we record all the control signals that are required for the desired computation in a memory chip and replace the pushbutton with a real clock. After doing that, the memory chip supplies the required control signals automatically and sequentially to the processor at every clock edge. These recorded control signals are called “machine code”.
4.2 “Machine Code” for Fish
Recall that each instruction of invertebrate must generate four control signals, ie,
- ALUOp (4 bits) ,
- Ra (3bits),
- Rb (3 bits)
- Rc (3 bits)
If these four control signals are concatenated together into an 13 bit entity, the result is called “a machine instruction” for fish. In each machine instruction, we have fields for ALUOp, Ra, Rb and Rc. The order of concatenation is arbitrary. We will use the ordering indicated in the figure below. Other orderings are also possible. But once we choose an ordering, we must stick with it, as the hardware is to be designed with that particular ordering in mind, and hardware will not understand any other ordering.
Each assembly language instruction has a corresponding machine language instruction and vice versa. Hence it is possible to translate between them.
In the following table, we give some assembly language instructions and their corresponding machine language translations as examples:
ASSEMBLY LANGUAGE | MACHINE LANGUAGE INSTRUCTION (binary) | MACHINE LANGUAGE INSTRUCTION (hex) |
---|---|---|
and 3 1 2 | 001 010 0010 010 | 0x512 |
or 0 3 0 | 000 011 0011 000 | 0x198 |
inc 5 | 101 ddd 0111 101 | 0x143D |
dec 2 | 010 ddd 1000 010 | 0x842 |
not 0 3 | 011 ddd 010 1000 | 0xC28 |
mov 5 7 | 111 ddd 0110 101 | 0x1C35 |
sub 7 2 1 | 010 001 0001 111 | 0x88F |
xor 1 1 1 | 001 001 0100 001 | 0x4A1 |
In Fish, we had needed a human operator to enter REG1CHOOSE, REG2CHOOSE, ALUOP and REGSELECT at every clock cycle. In frog, we store these commands into a memory chip whose data bus width is 13 bits, starting from address 0x000. We arbitrarily choose 10-bit for the address width. Hence, our program can be at most 1024 instructions long.
As an example, consider the following 4 instructions long program written in assembly:
and 3 1 2 or 0 3 0 inc 4 dec 3
The machine code corresponding to this program is
0X512 0x030 0x103C 0xC43
Before the start of the execution, this machine code must be written into the memory between the addresses 0x000-0x003. In other words, after being written, the contents of the memory must be like
address data ======== ===== 0x000 0x512 0x001 0x030 0x002 0x103C 0x003 0xC43 0x004 0xddd // d is don't care //from the address 0x004 down, memory will be empty.
At every clock cycle
- At the start of the operation, PC contains zero and the machine code is loaded into memory. Address bus of memory is 0x000 and the Dout of memory contains the first machine instruction.
Exercise: Assume that we use a different concatenation ordering. How would the diagram change?
4.3 Programming the Fish
Contrary to Fish, Frog is programmable.
The program must be already loaded into the memory at the start of the operation. Each location in memory
How the program is loaded into memory is left unspecified.
4.4 Example programs
4.5 Assembler for Fish
This assembler converts Fish assembly code into Fish machine code. Fill in the missing parts. Also, ordering of the fields ALUOP, Ra, Rb and Rc is wrong. Correct it.
#include <stdio.h> #include <stdlib.h> #include <string.h> //Converts a hexadecimal string to integer. int hex2int( char* hex) { int result=0; while ((*hex)!='\0') { if (('0'<=(*hex))&&((*hex)<='9')) result = result*16 + (*hex) -'0'; else if (('a'<=(*hex))&&((*hex)<='f')) result = result*16 + (*hex) -'a'+10; else if (('A'<=(*hex))&&((*hex)<='F')) result = result*16 + (*hex) -'A'+10; hex++; } return(result); } main() { FILE *fp; char line[100]; char *token = NULL; char *op1, *op2, *op3, *label; char ch; int chch; int program[1000]; int counter=0; //holds the address of the machine code instruction fp = fopen("name_of_program","r"); while(fgets(line,sizeof line,fp)!= NULL) { token=strtok(line,"\n\t\r "); //get the instruction mnemonic or labe if (strcmp(token,"add")==0) //-------- ADD --------- { op1 = strtok(NULL,"\n\t\r "); op2 = strtok(NULL,"\n\t\r "); op3 = strtok(NULL,"\n\t\r "); chch = (op1[0]-48)| ((op2[0]-48)<<3)|((op3[0]-48)<<6); program[counter]=0x7000+((chch)&0x00ff); counter++; } else if (strcmp(token,"sub")==0) { //to be added } else if (strcmp(token,"and")==0) { //to be added } else if (strcmp(token,"or")==0) { //to be added } else if (strcmp(token,"xor")==0) { //to be added } else if (strcmp(token,"not")==0) { op1 = strtok(NULL,"\n\t\r "); op2 = strtok(NULL,"\n\t\r "); ch = (op1[0]-48)| ((op2[0]-48)<<3); program[counter]=0x7500+((ch)&0x00ff); counter++; } else if (strcmp(token,"mov")==0) { //to be added } else if (strcmp(token,"inc")==0) { op1 = strtok(NULL,"\n\t\r "); ch = (op1[0]-48)| ((op1[0]-48)<<3); program[counter]=0x7700+((ch)&0x00ff); counter++; } else if (strcmp(token,"dec")==0) { //to be added } else //------WHAT IS ENCOUNTERED IS NOT A VALID INSTRUCTION OPCODE { printf("no valid opcode\n"); } } //while fclose(fp); fp = fopen("RAM","w"); fprintf(fp,"v2.0 raw\n"); //needed for logisim, remove this line for verilog.. for (i=0;i<counter+dataarea;i++) //complete this for memory size in verilog fprintf(fp,"%04x\n",program[i]); } //main