//addition .code ldi 3 0xb00 loop ldi 2 0x901 ld 0 2 ldi 1 0x1 and 1 0 1 jz loop ldi 2 0x900 ld 0 2 ldi 7 0x000f xor 7 0 7 jz pressed add 4 6 6 add 6 6 6 add 6 6 6 add 6 6 6 add 6 4 6 add 6 0 6 st 3 6 jmp loop pressed st 3 0 add 5 5 6 st 3 5 xor 6 6 6 jmp loop
Main Module
//Main module
module top_module ( output wire [3:0] rowwrite,
input [3:0] colread,
input clk,
output wire [3:0] grounds,
output wire [6:0] display,
input pushbutton // can be used as clock signal
);
reg [15:0] data_all;
wire [3:0] keyout;
reg [25:0] clk1;
reg [1:0] ready_buffer;
reg ack;
reg statusordata;
//memory map is defined here
localparam BEGINMEM=12'h000,
ENDMEM=12'h1ff,
KEYPAD=12'h900,
SEVENSEG=12'hb00;
// memory chip
reg [15:0] memory [0:127];
// cpu's input-output pins
wire [15:0] data_out;
reg [15:0] data_in;
wire [11:0] address;
wire memwt;
sevensegment ss1 (.datain(data_all), .grounds(grounds), .display(display), .clk(clk));
keypad_ex kp1(.rowwrite(rowwrite),.colread(colread),.clk(clk),.keyout(keyout),.statusordata(statusordata),.ack(ack));
reptile rr1 (.data_in(data_in), .data_out(data_out), .clk(clk), .memwt(memwt), .address(address));
//multiplexer for cpu input
always @*
if ( (BEGINMEM<=address) && (address<=ENDMEM) )
begin
data_in=memory[address];
ack=0;
statusordata=0;
end
else if (address==KEYPAD+1)
begin
statusordata=1;
data_in=keyout;
ack=0;
end
else if (address==KEYPAD)
begin
data_in=keyout;
statusordata=0;
ack=1;
end
else
begin
data_in=16'hf345;
ack=0;
statusordata=0;
end
//multiplexer for cpu output
always @(posedge clk) //data output port of the cpu
if (memwt)
if ( (BEGINMEM<=address) && (address<=ENDMEM) )
memory[address]<=data_out;
else if ( SEVENSEG==address)
data_all<=data_out;
initial
begin
data_all=0;
ack=0;
statusordata=0;
$readmemh("ram.dat", memory);
end
endmoduleKeypad Module
//Keypad Module
module keypad_ex (
output reg [3:0] rowwrite,
input [3:0] colread,
input clk,
input ack,
input statusordata,
output reg [15:0] keyout
);
wire keypressed;
reg [25:0] clk1;
reg ready;
reg [3:0] keyread, data;
reg [3:0] rowpressed;
reg [3:0] pressedcol [0:3];
reg [11:0] rowpressed_buffer0, rowpressed_buffer1, rowpressed_buffer2, rowpressed_buffer3;
reg [3:0] rowpressed_debounced;
always @(posedge clk)
clk1<=clk1+1;
always @(posedge clk1[15])
rowwrite<={rowwrite[2:0], rowwrite[3]};
always @(posedge clk1[15])
if (rowwrite== 4'b1110)
begin
rowpressed[0]<= ~(&colread); //colread=1111--> none of them pressed, colread=1110 --> 1, colread=1101-->2, 1011-->3, 0111->A
pressedcol[0]<=colread;
end
else if (rowwrite==4'b1101)
begin
rowpressed[1]<= ~(&colread); //colread=1111--> none of them pressed, colread=1110 --> 4, colread=1101-->5, 1011-->6, 0111->B
pressedcol[1]<=colread;
end
else if (rowwrite==4'b1011)
begin
rowpressed[2]<= ~(&colread); //colread=1111--> none of them pressed, colread=1110 --> 7, colread=1101-->8, 1011-->9, 0111->C
pressedcol[2]<=colread;
end
else if (rowwrite==4'b0111)
begin
rowpressed[3]<= ~(&colread); //colread=1111--> none of them pressed, colread=1110 --> *(E), colread=1101-->0, 1011-->#(F), 0111->D
pressedcol[3]<=colread;
end
wire transition0_10;
wire transition0_01;
assign transition0_10=~|rowpressed_buffer0;
assign transition0_01=&rowpressed_buffer0;
wire transition1_10;
wire transition1_01;
assign transition1_10=~|rowpressed_buffer1;
assign transition1_01=&rowpressed_buffer1;
wire transition2_10;
wire transition2_01;
assign transition2_10=~|rowpressed_buffer2;
assign transition2_01=&rowpressed_buffer2;
wire transition3_10;
wire transition3_01;
assign transition3_10=~|rowpressed_buffer3; //kpd=1-->0
assign transition3_01=&rowpressed_buffer3; //kpd=0-->1
always @(posedge clk1[15])
begin
rowpressed_buffer0<= {rowpressed_buffer0[10:0],rowpressed[0]};
if (rowpressed_debounced[0]==0 && transition0_01)
rowpressed_debounced[0]<=1;
if (rowpressed_debounced[0]==1 && transition0_10)
rowpressed_debounced[0]<=0;
rowpressed_buffer1<= {rowpressed_buffer1[10:0],rowpressed[1]};
if (rowpressed_debounced[1]==0 && transition1_01)
rowpressed_debounced[1]<=1;
if (rowpressed_debounced[1]==1 && transition1_10)
rowpressed_debounced[1]<=0;
rowpressed_buffer2<= {rowpressed_buffer2[10:0],rowpressed[2]};
if (rowpressed_debounced[2]==0 && transition2_01)
rowpressed_debounced[2]<=1;
if (rowpressed_debounced[2]==1 && transition2_10)
rowpressed_debounced[2]<=0;
rowpressed_buffer3<= {rowpressed_buffer3[10:0],rowpressed[3]};
if (rowpressed_debounced[3]==0 && transition3_01)
rowpressed_debounced[3]<=1;
if (rowpressed_debounced[3]==1 && transition3_10)
rowpressed_debounced[3]<=0;
end
always @*
begin
if (rowpressed_debounced[0]==1)
begin
if (pressedcol[0]==4'b1110)
keyread=4'h1;
else if (pressedcol[0]==4'b1101)
keyread=4'h2;
else if (pressedcol[0]==4'b1011)
keyread=4'h3;
else if (pressedcol[0]==4'b0111)
keyread=4'hA;
else keyread=4'b0000;
end
else if (rowpressed_debounced[1]==1)
begin
if (pressedcol[1]==4'b1110)
keyread=4'h4;
else if (pressedcol[1]==4'b1101)
keyread=4'h5;
else if (pressedcol[1]==4'b1011)
keyread=4'h6;
else if (pressedcol[1]==4'b0111)
keyread=4'hB;
else keyread=4'b0000;
end
else if (rowpressed_debounced[2]==1)
begin
if (pressedcol[2]==4'b1110)
keyread=4'h7;
else if (pressedcol[2]==4'b1101)
keyread=4'h8;
else if (pressedcol[2]==4'b1011)
keyread=4'h9;
else if (pressedcol[2]==4'b0111)
keyread=4'hC;
else keyread=4'b0000;
end
else if (rowpressed_debounced[3]==1)
begin
if (pressedcol[3]==4'b1110)
keyread=4'hE;
else if (pressedcol[3]==4'b1101)
keyread=4'h0;
else if (pressedcol[3]==4'b1011)
keyread=4'hF;
else if (pressedcol[3]==4'b0111)
keyread=4'hD;
else keyread=4'b0000;
end
else keyread=4'b0000;
end //always
assign keypressed= rowpressed_debounced[0]||rowpressed_debounced[1]||rowpressed_debounced[2]||rowpressed_debounced[3];
reg [1:0] keypressed_buffer; //yeni karakter için parmağı çekip tekrar basmamız için gerekli
always @(posedge clk)
keypressed_buffer<={keypressed_buffer[0],keypressed};
always @(posedge clk)
if ((keypressed_buffer==2'b01)&&(ready==0))
begin
data<=keyread;
ready<=1;
end
else if ((ack==1)&&(ready==1))
ready<=0;
always @(*)
if (statusordata==1)
keyout={15'b0,ready};
else
keyout={12'b0,data};
initial
begin
rowwrite=4'b1110;
ready=0;
end
endmodule
CPU Module
//Reptile CPU
module reptile (
input clk,
input [15:0] data_in,
output [15:0] data_out,
output reg [11:0] address,
output memwt
);
reg [11:0] pc, ir; //program counter, instruction register
reg [4:0] state; //FSM
reg [15:0] regbank [7:0];//registers
reg zeroflag; //zero flag register
reg [15:0] result; //output for result
localparam FETCH=4'b0000,
LDI=4'b0001,
LD=4'b0010,
ST=4'b0011,
JZ=4'b0100,
JMP=4'b0101,
ALU=4'b0111;
wire zeroresult; //zeroflag value
always @(posedge clk)
case(state)
FETCH:
begin
if ( data_in[15:12]==JZ) // if instruction is jz
if (zeroflag) //and if last bit of 7th register is 0 then jump to jump instruction state
state <= JMP;
else
state <= FETCH; //stay here to catch next instruction
else
state <= data_in[15:12]; //read instruction opcode and jump the state of the instruction to be read
ir<=data_in[11:0]; //read instruction details into instruction register
pc<=pc+1; //increment program counter
end
LDI:
begin
regbank[ ir[2:0] ] <= data_in; //if inst is LDI get the destination register number from ir and move the data in it.
pc<=pc+1; //for next instruction (32 bit instruction)
state <= FETCH;
end
LD:
begin
regbank[ir[2:0]] <= data_in;
state <= FETCH;
end
ST:
begin
state <= FETCH;
end
JMP:
begin
pc <= pc+ir;
state <= FETCH;
end
ALU:
begin
regbank[ir[2:0]]<=result;
zeroflag<=zeroresult;
state <= FETCH;
end
endcase
always @*
case (state)
LD: address=regbank[ir[5:3]][11:0];
ST: address=regbank[ir[5:3]][11:0];
default: address=pc;
endcase
assign memwt=(state==ST);
assign data_out = regbank[ir[8:6]];
always @*
case (ir[11:9])
3'h0: result = regbank[ir[8:6]]+regbank[ir[5:3]]; //000
3'h1: result = regbank[ir[8:6]]-regbank[ir[5:3]]; //001
3'h2: result = regbank[ir[8:6]]®bank[ir[5:3]]; //010
3'h3: result = regbank[ir[8:6]]|regbank[ir[5:3]]; //011
3'h4: result = regbank[ir[8:6]]^regbank[ir[5:3]]; //100
3'h7: case (ir[8:6])
3'h0: result = !regbank[ir[5:3]];
3'h1: result = regbank[ir[5:3]];
3'h2: result = regbank[ir[5:3]]+1;
3'h3: result = regbank[ir[5:3]]-1;
default: result=16'h0000;
endcase
default: result=16'h0000;
endcase
assign zeroresult = ~|result;
initial begin;
state=FETCH;
zeroflag=0;
pc=0;
end
endmoduleReptile Assembler
// to compile, gcc assembler.c -o assembler
// No error check is provided.
// Variable names cannot start with numeric characters, ie, with 0-9.
// hexadecimals are twos complement.
// first address of the code section is zero, and the data section follows the code section in memory.
// four tables are formed: jump table, ldi table, label table and variable table.
#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
struct label_or_variable
{
int location;
char *name;
};
// A label is a symbol which mark a location within the code section. In the example
// program above, the strings "lpp", "loop" and "lp1" are labels.
// In reptile, labels are used by jump, jz and ldi instructions.
struct label_or_variable labeltable[50]; //there can be 50 labels at most in our programs
int nooflabels = 0; //number of labels encountered during assembly.
// A variable is a symbol which mark a location within the data section. In the example
// program above, the strings "", "" and "" are variables.
// In reptile, variables are used by ldi instructions.
struct label_or_variable variabletable[50]; // The list of variables in .data section and their locations.
int noofvariables = 0; //number of jumps encountered during assembly.
// Jump instructions cannot be assembled readily because we may not know the value of
// the label when we encountered a jump instruction. This happens if the label used by
// that jump instruction appear below that jump instruction. This is the situation
// with the label "loop" in the example program above. Hence, the location of jump
// instructions must be stored.
struct label_or_variable jumptable[100]; //There can be at most 100 jumps
int noofjumps=0; //number of jump instructions encountered during assembly.
//Variables and labels are used by ldi instructions.
//The memory for the variables are traditionally allocated at the end of the code section.
//Hence their addresses are not known when we assemble a ldi instruction. Also, the value of
//a label may not be known when we encounter a ldi instruction which uses that label.
//Hence, the location of the ldi instructions must be kept, and these instructions must be
//modified when we discover the address of the label or variable that it uses.
struct label_or_variable lditable[100];
int noofldis=0;
fp = fopen("code.txt","r");
if (fp != NULL)
{
while(fgets(line,sizeof line,fp)!= NULL) //skip till .code section
{
token=strtok(line,"\n\t\r ");
if (strcmp(token,".code")==0 )
break;
}
while(fgets(line,sizeof line,fp)!= NULL)
{
token=strtok(line,"\n\t\r "); //get the instruction mnemonic or label
//======================================== FIRST PASS ======================================================
while (token)
{
if (strcmp(token,"ldi")==0) //---------------LDI INSTRUCTION--------------------
{
op1 = strtok(NULL,"\n\t\r "); //get the 1st operand of ldi, which is the register that ldi loads
op2 = strtok(NULL,"\n\t\r "); //get the 2nd operand of ldi, which is the data that is to be loaded
program[counter]=0x1000+hex2int(op1); //generate the first 16-bit of the ldi instruction
counter++; //move to the second 16-bit of the ldi instruction
if ((op2[0]=='0')&&(op2[1]=='x')) //if the 2nd operand is twos complement hexadecimal
program[counter]=hex2int(op2+2)&0xffff; //convert it to integer and form the second 16-bit
else if (( (op2[0])=='-') || ((op2[0]>='0')&&(op2[0]<='9'))) //if the 2nd operand is decimal
program[counter]=atoi(op2)&0xffff; //convert it to integer and form the second 16-bit
else //if the second operand is not decimal or hexadecimal, it is a laber or a variable.
{ //in this case, the 2nd 16-bits of the ldi instruction cannot be generated.
lditable[noofldis].location = counter; //record the location of this 2nd 16-bit
op1=(char*)malloc(sizeof(op2)); //and the name of the label/variable that it must contain
strcpy(op1,op2); //in the lditable array.
lditable[noofldis].name = op1;
noofldis++;
}
counter++; //skip to the next memory location
}
else if (strcmp(token,"ld")==0) //------------LD INSTRUCTION---------------------
{
op1 = strtok(NULL,"\n\t\r "); //get the 1st operand of ld, which is the destination register
op2 = strtok(NULL,"\n\t\r "); //get the 2nd operand of ld, which is the source register
ch = (op1[0]-48)| ((op2[0]-48) << 3); //form bits 11-0 of machine code. 48 is ASCII value of '0'
program[counter]=0x2000+((ch)&0x00ff); //form the instruction and write it to memory
counter++; //skip to the next empty location in memory
}
else if (strcmp(token,"st")==0) //-------------ST INSTRUCTION--------------------
{
op1 = strtok(NULL,"\n\t\r "); //get the 1st operand of ld, which is the destination register
op2 = strtok(NULL,"\n\t\r "); //get the 2nd operand of ld, which is the source register
chch = (op1[0]-48)<<3| ((op2[0]-48) << 6); //form bits 11-0 of machine code. 48 is ASCII value of '0'
program[counter]=0x3000+((chch)&0x01ff); //form the instruction and write it to memory
counter++; //skip to the next empty location in memory
//to be added
}
else if (strcmp(token,"jz")==0) //------------- CONDITIONAL JUMP ------------------
{
op1 = strtok(NULL,"\n\t\r "); //read the label string
jumptable[noofjumps].location = counter; //write the jz instruction's location into the jumptable
op2=(char*)malloc(sizeof(op1)); //allocate space for the label
strcpy(op2,op1); //copy the label into the allocated space
jumptable[noofjumps].name=op2; //point to the label from the jumptable
noofjumps++; //skip to the next empty location in jumptable
program[counter]=0x4000; //write the incomplete instruction (just opcode) to memory
counter++;
//to be added
}
else if (strcmp(token,"jmp")==0) //-------------- JUMP -----------------------------
{
op1 = strtok(NULL,"\n\t\r "); //read the label string
jumptable[noofjumps].location = counter; //write the jz instruction's location into the jumptable
op2=(char*)malloc(sizeof(op1)); //allocate space for the label
strcpy(op2,op1); //copy the label into the allocated space
jumptable[noofjumps].name=op2; //point to the label from the jumptable
noofjumps++; //skip to the next empty location in jumptable
program[counter]=0x5000; //write the incomplete instruction (just opcode) to memory
counter++; //skip to the next empty location in memory.
}
else 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)<<6)|((op3[0]-48)<<3);
program[counter]=0x7000+((chch)&0x01ff);
counter++;
}
else if (strcmp(token,"sub")==0)
{
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)<<6)|((op3[0]-48)<<3);
program[counter]=0x7200+((chch)&0x01ff);
counter++;
//to be added
}
else if (strcmp(token,"and")==0)
{
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)<<6)|((op3[0]-48)<<3);
program[counter]=0x7400+((chch)&0x01ff);
counter++;
//to be added
}
else if (strcmp(token,"or")==0)
{
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)<<6)|((op3[0]-48)<<3);
program[counter]=0x7600+((chch)&0x01ff);
counter++;//to be added
}
else if (strcmp(token,"xor")==0)
{
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)<<6)|((op3[0]-48)<<3);
program[counter]=0x7800+((chch)&0x01ff);
counter++;
//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]=0x7E00+((ch)&0x00ff);
counter++;
}
else if (strcmp(token,"mov")==0)
{
op1 = strtok(NULL,"\n\t\r ");
op2 = strtok(NULL,"\n\t\r ");
ch = (op1[0]-48)| ((op2[0]-48)<<3);
program[counter]=0x7E40+((ch)&0x00ff);
counter++;
//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]=0x7E80+((ch)&0x00ff);
counter++;
}
else if (strcmp(token,"dec")==0)
{
op1 = strtok(NULL,"\n\t\r ");
ch = (op1[0]-48)| ((op1[0]-48)<<3);
program[counter]=0x7EC0+((ch)&0x00ff);
counter++; //to be added
}
else //------WHAT IS ENCOUNTERED IS NOT AN INSTRUCTION BUT A LABEL. UPDATE THE LABEL TABLE--------
{
labeltable[nooflabels].location = counter; //read the label and update labeltable.
op1=(char*)malloc(sizeof(token));
strcpy(op1,token);
labeltable[nooflabels].name=op1;
nooflabels++;
}
token = strtok(NULL,",\n\t\r "); // if what is read before is an instruction, this will be NULL
//if what is read before is an label, this will be an opcode.
}
}
//================================= SECOND PASS ==============================
//supply the address fields of the jump and jz instructions by matching jumptable and labeltable
int i,j;
for (i=0; i<noofjumps;i++) //for all jump/jz instructions encountered
{
j=0;
while ((j<nooflabels)&&( strcmp(jumptable[i].name , labeltable[j].name ) != 0 )) //if the label for this jump/jz does not match with the
j++; // jth label in the labeltable, check the next label..
program[jumptable[i].location] +=(labeltable[j].location-jumptable[i].location-1)&0x0fff; //copy the jump address into memory.
}
//search for the start of the .data segment
rewind(fp);
while(fgets(line,sizeof line,fp)!= NULL) //skip till .data, if no .data, also ok.
{
token=strtok(line,"\n\t\r ");
if (strcmp(token,".data")==0 )
break;
}
// process the .data segment and generate the variabletable[] array.
int dataarea=0;
while(fgets(line,sizeof line,fp)!= NULL)
{
token=strtok(line,"\n\t\r ");
if (strcmp(token,".code")==0 ) //go till the .code segment
break;
else if (token[strlen(token)-1]==':')
{
token[strlen(token)-1]='\0'; //will not cause memory leak, as we do not do malloc
variabletable[noofvariables].location=counter+dataarea;
op1=(char*)malloc(sizeof(token));
strcpy(op1,token);
variabletable[noofvariables].name=op1;
token = strtok(NULL,",\n\t\r ");
if (token==NULL)
program[counter+dataarea]=0;
else if (strcmp(token, ".space")==0)
{
token=strtok(NULL,"\n\t\r ");
dataarea+=atoi(token);
}
else if((token[0]=='0')&&(token[1]=='x'))
program[counter+dataarea]=hex2int(token+2)&0xffff;
else if (( (token[0])=='-') || ('0'<=(token[0])&&(token[0]<='9')) )
program[counter+dataarea]=atoi(token)&0xffff;
noofvariables++;
dataarea++;
}
}
// supply the address fields for the ldi instructions from the variable table
for( i=0; i<noofldis;i++)
{
j=0;
while ((j<noofvariables)&&( strcmp( lditable[i].name , variabletable[j].name)!=0 ))
j++;
if (j<noofvariables)
program[lditable[i].location] = variabletable[j].location;
}
// supply the address fields for the ldi instructions from the label table
for( i=0; i<noofldis;i++)
{
j=0;
while ((j<nooflabels)&&( strcmp( lditable[i].name , labeltable[j].name)!=0 ))
j++;
if (j<nooflabels){
program[lditable[i].location] = (labeltable[j].location)&0x0fff;
printf("%d %d %d\n", i, j, (labeltable[j].location));
}
}
//display the resulting tables
printf("LABEL TABLE\n");
for (i=0;i<nooflabels;i++)
printf("%d %s\n", labeltable[i].location, labeltable[i].name);
printf("\n");
printf("JUMP TABLE\n");
for (i=0;i<noofjumps;i++)
printf("%d %s\n", jumptable[i].location, jumptable[i].name);
printf("\n");
printf("VARIABLE TABLE\n");
for (i=0;i<noofvariables;i++)
printf("%d %s\n", variabletable[i].location, variabletable[i].name);
printf("\n");
printf("LDI INSTRUCTIONS\n");
for (i=0;i<noofldis;i++)
printf("%d %s\n", lditable[i].location, lditable[i].name);
printf("\n");
fclose(fp);
fp = fopen("RAM","w");
fprintf(fp,"v2.0 raw\n");
for (i=0;i<counter+dataarea;i++)
fprintf(fp,"%04x\n",program[i]);
fclose(fp);
fp = fopen("ram.dat","w");
for (i=0;i<counter+dataarea;i++)
fprintf(fp, "%04x\n", program[i]);
}
}