s502 assembler
A very simple assembler for the 6502 line of processors written in C
instructions.c
Go to the documentation of this file.
1 #include "debugmalloc.h"
2 
3 #include <stdio.h>
4 #include <errno.h>
5 
6 #include "logging.h"
7 #include "number.h"
8 #include "addressmode.h"
9 #include "instructions.h"
10 #include "util.h"
11 
19  FILE* f = fopen(fname, "r");
20  if (f == NULL) {
21  ERROR("An error occured opening the file %s!\n", fname);
22  ERROR("Error opening file: %s\n", strerror(errno));
23  return NULL;
24  }
25 
26  int rowindex = 0;
27  char buff[16];
28 
29  int ptr = 0;
30  int row = 1;
31  Instruction* list = malloc(sizeof(Instruction));
32 
33  // ignore first line
34  // (Also possibly has BOM for unicode)
35  int x;
36  while (x = fgetc(f), x != '\n' && x != EOF);
37  if (x == EOF) {
38  goto ERR_MALFORMED;
39  }
40  if (list == NULL) goto ERR_MEM;
41  list->next = NULL;
42  Instruction* curr = list;
43 
44 
45  while (x = fgetc(f), x != EOF) {
46  if (x == '\r') continue; // quick and dirty fix for linux opening a windows file
47  if (x == ';' || x == '\n') {
48  // end of column
49  buff[ptr] = 0;
50 
51  // process data
52  if (rowindex == 0) {
53  if (ptr != 3) goto ERR_MALFORMED;
54  memcpy(curr->mnem, buff, 3);
55  curr->mnem[3] = 0;
56  } else {
57  if (ptr != 2 && ptr != 0) goto ERR_MALFORMED;
58  if (ptr)
59  curr->opcs[rowindex - 1] = 16 * number_char_to_digit(buff[0]) + number_char_to_digit(buff[1]);
60  else
61  curr->opcs[rowindex - 1] = OPC_INVALID;
62  }
63  ptr = 0;
64  rowindex++;
65  if (x == '\n') {
66  if (rowindex != 14)
67  goto ERR_MALFORMED;
68  rowindex = 0;
69  row++;
70 
71  curr->next = malloc(sizeof(Instruction));
72  if (curr->next == NULL) goto ERR_MEM;
73  curr->next->next = NULL;
74  curr = curr->next;
75  }
76 
77 
78  continue;
79  }
80  buff[ptr++] = x;
81  }
82 
83  // file might had a trailing newline
84  // in that case the last entry is not valid
85 
86  if (rowindex == 0) {
87  for (curr = list; curr->next != NULL && curr->next->next != NULL; curr = curr->next);
88  free(curr->next);
89  curr->next = NULL;
90  }
91 
92  fclose(f);
93  return list;
94 ERR_MALFORMED:
95  ERROR("Malformed instruction line:column: %d : %d\n", row + 1, rowindex + 1);
96  ERROR("Malformed instructions/opcodes file: %s\n", fname);
97  goto CLEANUP;
98 
99 ERR_MEM:
100  ERROR("Memory allocation error in instruction_load()!\n");
101  goto CLEANUP;
102 
103 CLEANUP:
104  instruction_free(list);
105  fclose(f);
106 
107  return NULL;
108 }
109 
110 
112  Instruction* ptr;
113  for (ptr = list; ptr != NULL; ptr = ptr->next) {
114  if (util_match_string(mnem, ptr->mnem, 3) == 0)
115  return ptr;
116  }
117  return NULL;
118 }
119 
120 
122  if (!list) return;
123  while (list->next != NULL) {
124  Instruction* ptr = list->next;
125  list->next = ptr->next;
126  free(ptr);
127  }
128  free(list);
129 }
130 
131 
133  printf("%s", instr->mnem);
134  for (int i = 0; i < ADRM_COUNT; i++)
135  if (instr->opcs[i] != OPC_INVALID) {
136  printf("\t%s:\t%x\n", ADRM_NAMES[i], instr->opcs[i]);
137  }
138  printf("\n");
139 }
140 
142  for (; list != NULL; list = list->next) {
143  instruction_print(list);
144  }
145 }
ADRM_NAMES
const char * ADRM_NAMES[]
Human-readable names of address modes.
Definition: addressmode.c:16
ADRM_COUNT
@ ADRM_COUNT
Total number of addressing modes.
Definition: addressmode.h:51
Instruction::instruction_free
void instruction_free(Instruction *list)
free all memory associated with an Instruction* list
Definition: instructions.c:121
Instruction::instruction_print_all
void instruction_print_all(Instruction *list)
debug-print all instructions in a list
Definition: instructions.c:141
Instruction::mnem
char mnem[4]
3-letter mnemonic of an instruction + trailing 0
Definition: instructions.h:27
Instruction::next
struct Instruction * next
Next instruction pointer on NULL.
Definition: instructions.h:31
Instruction::instruction_print
void instruction_print(Instruction *instr)
fancy-print one instruction data
Definition: instructions.c:132
Instruction::instruction_load
Instruction * instruction_load(char *fname)
Load instruction data from CSV file.
Definition: instructions.c:18
addressmode.h
AddressMode enum and related data.
util_match_string
int util_match_string(char *first, char *second, int count)
case-insensitive memcmp
Definition: util.c:32
Instruction
linked list member holding instruction data
Definition: instructions.h:25
instructions.h
Instruction data and related operations.
logging.h
logging and fancy-printing
Instruction::opcs
unsigned char opcs[ADRM_COUNT]
Different combinarions of this instruction. Invalid ones are set to OPC_INVALID.
Definition: instructions.h:29
number_char_to_digit
int number_char_to_digit(char c)
Convert a hex char to a digit.
Definition: number.c:12
Instruction::instruction_find
Instruction * instruction_find(Instruction *list, char *mnem)
find the Instruction entry for a given mnemonic
Definition: instructions.c:111
number.h
Number module to parse numbers.
util.h
various utility functions
OPC_INVALID
@ OPC_INVALID
An invalid opcode to signal invalid / non-existent variations.
Definition: instructions.h:15
ERROR
#define ERROR(...)
Fancy-print an error (cause of faliure). Works like printf.
Definition: logging.h:40