blob: e04c78e6f816cb77c283d313a189987f37b149eb [file] [log] [blame]
/*
* Copyright 2021 cpu-dev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <stdint.h>
#include <ctype.h>
//#define DEBUG
#define MODE_BIN 0
#define MODE_VERILOG 1
struct label {
char name;
uint8_t addr;
struct label *next;
};
struct label *head;
typedef enum {
MOV = 0,
ADD,
AND = 3,
OR,
NOT,
SLL,
SRL,
SRA,
CMP,
JE,
JMP,
LDIH,
LDIL,
LD,
ST,
IRET,
LDI
} inst_t;
typedef enum {
R0,
R1,
R2,
R3
} reg_t;
int8_t
opcode(char *mnemonic)
{
if(!strncmp(mnemonic, "mov", 3))
return MOV;
if(!strncmp(mnemonic, "add", 3))
return ADD;
if(!strncmp(mnemonic, "and", 3))
return AND;
if(!strncmp(mnemonic, "or", 2))
return OR;
if(!strncmp(mnemonic, "not", 3))
return NOT;
if(!strncmp(mnemonic, "sll", 3))
return SLL;
if(!strncmp(mnemonic, "srl", 3))
return SRL;
if(!strncmp(mnemonic, "sra", 3))
return SRA;
if(!strncmp(mnemonic, "cmp", 3))
return CMP;
if(!strncmp(mnemonic, "je", 2))
return JE;
if(!strncmp(mnemonic, "jmp", 3))
return JMP;
if(!strncmp(mnemonic, "ldih", 4))
return LDIH;
if(!strncmp(mnemonic, "ldil", 4))
return LDIL;
if(!strncmp(mnemonic, "ldi", 3))
return LDI;
if(!strncmp(mnemonic, "ld", 2))
return LD;
if(!strncmp(mnemonic, "st", 2))
return ST;
if(!strncmp(mnemonic, "iret", 4))
return IRET;
return -1;
}
void
new_label(char name, int addr)
{
struct label *p;
p = head;
while(p->next != NULL)
p = p->next;
p->next = (struct label *)malloc(sizeof(struct label));
p->next->name = name;
p->next->addr = addr;
p->next->next = NULL;
}
uint8_t
search_label(char name)
{
struct label *p;
p = head->next;
while(p != NULL) {
if(p->name == name) {
return p->addr;
}
p = p->next;
}
printf("unknown label referenced: %c\n", name);
exit(-1);
}
uint8_t
rs(char *p)
{
#ifdef DEBUG
printf("arguments(rs): %s\n", p);
#endif
return strtol(++p, &p, 16);
}
uint8_t
imm(char *p)
{
#ifdef DEBUG
printf("arguments(imm): %s\n", p);
#endif
return strtol(p, &p, 16);
}
uint8_t
ex_imm(char *p)
{
#ifdef DEBUG
printf("arguments(ex_imm): %s\n", p);
#endif
if(isalpha(*p))
return search_label(*p);
return strtol(p, &p, 16);
}
uint8_t
rdrs(char *p)
{
#ifdef DEBUG
printf("arguments(rd/rs): %s\n", p);
#endif
int rd, rs;
rd = strtol(++p, &p, 16);
while(isspace(*p) || *p == ',')
++p;
rs = strtol(++p, &p, 16);
return (rd << 2) + rs;
}
int
main(int argc, char *argv[])
{
char mode = MODE_BIN;
char buf[256];
char *p;
int8_t inst, result;
int i;
FILE *in, *out;
if((in = fopen(argv[1], "r")) == NULL) {
puts("file open error!");
return -1;
}
if(argc > 2) {
if(strncmp(argv[2], "verilog", 7) == 0)
mode = MODE_VERILOG;
}
if(mode == MODE_BIN) {
if((out = fopen("out.bin", "wb")) == NULL) {
puts("file open error!");
return -1;
}
}
else {
if((out = fopen("out.txt", "w")) == NULL) {
puts("file open error!");
return -1;
}
}
head = (struct label *)malloc(sizeof(struct label));
head->name = 0;
head->addr = 0;
head->next = NULL;
i = 0;
while(fgets(buf, 256, in) != NULL) {
if(*buf == '\n') continue;
p = buf;
while(isspace(*p)) ++p;
if(!strncmp(p, "//", 2)) continue;
inst = opcode(p);
while(isalpha(*p)) ++p;
if(*p == ':') {
#ifdef DEBUG
printf("new label in L%d: %c\n", i, *(p-1));
#endif
new_label(*(p-1), i);
}
else {
if(inst == LDI) ++i;
++i;
continue;
}
}
rewind(in);
i = 0;
while(fgets(buf, 256, in) != NULL) {
if(*buf == '\n') continue;
p = buf;
while(isspace(*p)) ++p;
if(!strncmp(p, "//", 2)) continue;
inst = opcode(p);
#ifdef DEBUG
printf("instruction number: %d\n", inst);
#endif
while(isalpha(*p)) ++p;
if(*p == ':') continue;
while(isspace(*p)) ++p;
switch(inst) {
case -1:
printf("invalid instruction!!!\n");
return -1;
case JE:
case JMP:
result = (inst << 4) | rs(p);
mode == MODE_BIN
? fwrite(&result, 1, 1, out)
: fprintf(out, "mem[%d] = 0x%02x;\n", i++, result & 0x000000ff);
break;
case LDIH:
case LDIL:
result = (inst << 4) | imm(p);
mode == MODE_BIN
? fwrite(&result, 1, 1, out)
: fprintf(out, "mem[%d] = 0x%02x;\n", i++, result & 0x000000ff);
break;
case IRET:
result = 0xb4;
mode == MODE_BIN
? fwrite(&result, 1, 1, out)
: fprintf(out, "mem[%d] = 0x%02x;\n", i++, result & 0x000000ff);
break;
case LDI:
result = (LDIH << 4) | (ex_imm(p) >> 4);
mode == MODE_BIN
? fwrite(&result, 1, 1, out)
: fprintf(out, "mem[%d] = 0x%02x;\n", i++, result & 0x000000ff);
result = (LDIL << 4) | (ex_imm(p) & 0x0f);
mode == MODE_BIN
? fwrite(&result, 1, 1, out)
: fprintf(out, "mem[%d] = 0x%02x;\n", i++, result & 0x000000ff);
break;
default:
result = (inst << 4) | rdrs(p);
mode == MODE_BIN
? fwrite(&result, 1, 1, out)
: fprintf(out, "mem[%d] = 0x%02x;\n", i++, result & 0x000000ff);
break;
}
}
return 0;
}