The Simplified Instructional Computer (SIC) and its extended version (SIC/XE) are theoretical machine architectures designed for learning about assemblers and machine-level programming. SIC/XE includes support for extended addressing modes, additional instructions, and registers, making it more versatile.
This project focuses on the implementation of a SIC/XE assembler that processes assembly code in two passes. The assembler incorporates the EQU directive to define symbols independently without introducing conflicts. The implementation uses C or C++ and outputs machine code for given assembly programs.
begin
read first input line
if OPCODE ='START' then
begin
save #[OPERAND] as starting address
initialize LOCCTR to starting address
write line to intermediate file
read next input line
end {if START}
else
initialize LOCCTR to 0
while OCODE != 'END' do
begin
if this is not a comment line then
begin
if there is a symbol in the LABEL field then
begin
search SYMTAB for LABEL
if found then
set error flag (duplicate symbol)
else
insert (LABEL,LOCCTR) into SYMTAB
end {if symbol}
search OPTAB for OPCODE
if found then
add 3 {instruction length} to LOCCTR
else if OPCODE='WORD' then
add 3 to LOCCTR
else if OPCODE = 'RESW' then
add 3 * #[OPERAND] to LOCCTR
else if OPCODE = 'RESB' then
add #[OPERAND] to LOCCTR
else if OPCODE = 'BYTE' then
begin
find length of constant in bytes
add length to LOCCTR
end {if BYTE}
else
set error flag (invalid operation code)
end {if not a comment}
write line to intermediate file
read next input line
end {while not END}
write last line to intermediate file
save (LOCCTR – starting address) as program length
end {Pass 1}
begin
read first input line (from intermediate file)
if OPCODE ='START' then
begin
write listing line
read next input line
end {if START}
write Header record to object program
initialize first Text record
while OPCODE != 'END' do
begin
if this is not a comment line then
begin
search OPTAB for OPCODE
if found then
begin
if there is a symbol in OPERAND field then
begin
search SYMTAB for OPERAND
if found then
store symbol value as operand address
else
begin
store 0 as operand address
set error flag (undefined symbol)
end
end {if symbol}
else
store 0 as operand address
assemble the object code instruction
end {if opcode found}
else if OPCODE ='BYTE' or 'WORD' then
convert constant to object code
if object code will not fit into the current Text record then
begin
write Text record to object program
initialize new Text record
end
add object code to Text record
end {if not comment}
write listing line
read next input line
end(while not END)
write last Text record to object program
write End record to object program
write last listing line
end{Pass 2}
Pass1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
char *decimalToHex(int decimal) {
static char hex_string[10];
sprintf(hex_string, "%X", decimal);
return hex_string;
}
int main() {
printf("PASS 1\n");
char str;
char saved_labels[20][20];
int saved_labels_index = 0;
char label[20], opcode[20], operand[20];
char optab_opcode[10], machine_code[10];
int starting_address, location_counter;
bool opcode_found = false;
FILE *input_file, *optab_file, *symtab_file, *output_file;
input_file = fopen("src.txt", "r");
optab_file = fopen("opcod.txt", "r");
symtab_file = fopen("symbo.txt", "w+");
output_file = fopen("inter.txt", "w");
if (input_file == NULL || optab_file == NULL || symtab_file == NULL || output_file == NULL) {
printf("Error! opening file");
exit(1);
}
fscanf(input_file, "%s %s %s", label, opcode, operand);
if (strcmp(opcode, "START") == 0) {
starting_address = strtol(operand, NULL, 16);
location_counter = starting_address;
fprintf(output_file, "%s\t%s\t%s\t%s\n", "-", label, opcode, operand);
fscanf(input_file, "%s %s %s", label, opcode, operand);
} else {
location_counter = 0;
starting_address = 0;
}
while (strcmp(opcode, "END") != 0) {
if (strcmp(opcode, "START") == 0 || strcmp(opcode, "END") == 0) {
fprintf(output_file, "%s\t%s\t%s\t%s\n", "-", label, opcode, operand);
} else if (strcmp(opcode, "EQU") == 0) {
if (operand[0] == '*') {
fprintf(symtab_file, "%s\t%s\n", label, decimalToHex(location_counter));
} else {
int value = atoi(operand);
fprintf(symtab_file, "%s\t%s\n", label, decimalToHex(value));
}
} else {
if (strcmp(label, "-") != 0) {
fprintf(symtab_file, "%s\t%s\n", label, decimalToHex(location_counter));
}
rewind(optab_file);
opcode_found = false;
fscanf(optab_file, "%s %s", optab_opcode, machine_code);
while (!feof(optab_file)) {
if (strcmp(opcode[0] == '+' ? opcode + 1 : opcode, optab_opcode) == 0) {
opcode_found = true;
break;
}
fscanf(optab_file, "%s %s", optab_opcode, machine_code);
}
fprintf(output_file, "%s\t%s\t%s\t%s\n", decimalToHex(location_counter), label, opcode, operand);
if (opcode_found) {
location_counter += (opcode[0] == '+') ? 4 : 3;
} else if (strcmp(opcode, "BYTE") == 0) {
if (operand[0] == 'C') {
location_counter += strlen(operand) - 3;
} else if (operand[0] == 'X') {
location_counter += (strlen(operand) - 3) / 2;
}
} else if (strcmp(opcode, "RESB") == 0) {
location_counter += atoi(operand);
} else if (strcmp(opcode, "WORD") == 0) {
location_counter += 3;
} else if (strcmp(opcode, "RESW") == 0) {
location_counter += 3 * atoi(operand);
} else {
printf("Error! Invalid opcode: %s\n", opcode);
exit(1);
}
}
fscanf(input_file, "%s %s %s", label, opcode, operand);
}
fprintf(output_file, "%s\t%s\t%s\t%s\n", decimalToHex(location_counter), label, opcode, operand);
printf("%s\t%s\t%s\t%s\n", decimalToHex(location_counter), label, opcode, operand);
printf("\nSize of the program: %s\n", decimalToHex(location_counter - starting_address));
fclose(input_file);
fclose(optab_file);
fclose(symtab_file);
fclose(output_file);
symtab_file = fopen("symbo.txt", "r");
if (symtab_file == NULL) {
printf("Error opening symbol table file!\n");
exit(1);
}
printf("\nThe contents of Symbol Table:\n\n");
char ch;
ch = fgetc(symtab_file);
while (ch != EOF) {
printf("%c", ch);
ch = fgetc(symtab_file);
}
fclose(symtab_file);
return 0;
}
Input:
TEN EQU 10
HALF EQU 2
FOUR EQU 4
START_ADDR EQU 1000
WORD_SIZE EQU 2
COPY START START_ADDR
- +LDA ALPHA
- ADD #TEN
- DIV #HALF
- STA BETA
- SUB #FOUR
- STA GAMMA
- +LDA GAMMA
- ADD #HALF
- +LDA BETA
- END START_ADDR
LDA 00
STA 0C
ADD 18
SUB 1C
MUL 20
DIV 24
COMP 28
TIX 2C
JEQ 30
JGT 34
JLT 38
JSUB 48
RSUB 4C
LDCH 50
STCH 54
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
// Function to write a text record
void writeTextRecord(FILE *output, const char *loc, const char *object_code) {
if (strlen(object_code) > 0) {
fprintf(output, "T^%06s^%s\n", loc, object_code);
}
}
int main() {
printf("\nPASS 2\n");
char loc[20], label[20], opcode[20], operand[20];
char optab_opcode[10], optab_machine_code[10];
char symtab_label[20], symtab_address[20];
FILE *intermediate, *output, *symtab, *optab;
// Open files
intermediate = fopen("inter.txt", "r");
output = fopen("object.txt", "w");
symtab = fopen("symbo.txt", "r");
optab = fopen("opcod.txt", "r");
if (intermediate == NULL || output == NULL || symtab == NULL || optab == NULL) {
printf("Error! Unable to open files\n");
exit(1);
}
// Read the first line for program start address
fscanf(intermediate, "%s %s %s %s", loc, label, opcode, operand);
int start = strtol(operand, NULL, 16);
// Write the header record
fprintf(output, "H^%s^%06X^2D\n", label, start);
// Process each instruction
fscanf(intermediate, "%s %s %s %s", loc, label, opcode, operand);
while (strcmp(opcode, "END") != 0) {
printf("Processing: %s - %s %s\n", loc, opcode, operand);
char object_code[10] = {0};
char effective_operand[10] = {0};
bool opcode_found = false;
// Search in OPTAB
rewind(optab);
while (fscanf(optab, "%s %s", optab_opcode, optab_machine_code) != EOF) {
if (strcmp(opcode[0] == '+' ? opcode + 1 : opcode, optab_opcode) == 0) {
opcode_found = true;
break;
}
}
if (opcode_found) {
// Determine addressing mode
if (operand[0] == '#') { // Immediate addressing
strcpy(effective_operand, operand + 1);
} else if (operand[0] == '@') { // Indirect addressing
strcpy(effective_operand, operand + 1);
} else { // Direct addressing
strcpy(effective_operand, operand);
}
// Search in SYMTAB for operand address
bool label_found = false;
rewind(symtab);
while (fscanf(symtab, "%s %s", symtab_label, symtab_address) != EOF) {
if (strcmp(symtab_label, effective_operand) == 0) {
label_found = true;
break;
}
}
// Generate object code
if (label_found) {
if (opcode[0] == '+') { // Format 4 instruction
sprintf(object_code, "%s1%s", optab_machine_code, symtab_address);
} else { // Format 3 instruction
sprintf(object_code, "%s%s", optab_machine_code, symtab_address);
}
} else {
sprintf(object_code, "%s000", optab_machine_code); // Default unresolved address
}
} else if (strcmp(opcode, "WORD") == 0) {
sprintf(object_code, "%06X", atoi(operand));
} else if (strcmp(opcode, "BYTE") == 0) {
for (int i = 2; i < strlen(operand) - 1; i++) {
sprintf(object_code + strlen(object_code), "%X", operand[i]);
}
}
// Write the T record for the current instruction
writeTextRecord(output, loc, object_code);
// Read next instruction
fscanf(intermediate, "%s %s %s %s", loc, label, opcode, operand);
}
// Write end record
fprintf(output, "E^%06X\n", start);
fclose(intermediate);
fclose(output);
fclose(symtab);
fclose(optab);
// Print the content of the object file
output = fopen("object.txt", "r");
if (output == NULL) {
printf("Error opening object file for reading!\n");
exit(1);
}
printf("\nContent of object file:\n");
char line[100];
while (fgets(line, sizeof(line), output) != NULL) {
printf("%s", line);
}
fclose(output);
return 0;
}
Intermediate
- COPY START START_ADDR
0 - +LDA ALPHA
4 - ADD #TEN
7 - DIV #HALF
A - STA BETA
D - SUB #FOUR
10 - STA GAMMA
13 - +LDA GAMMA
17 - ADD #HALF
1A - +LDA BETA
1E - END START_ADDR
Symbol
TEN A
HALF 2
FOUR 4
START_ADDR 3E8
WORD_SIZE 2
LDA 00
STA 0C
ADD 18
SUB 1C
MUL 20
DIV 24
COMP 28
TIX 2C
JEQ 30
JGT 34
JLT 38
JSUB 48
RSUB 4C
LDCH 50
STCH 54
Output