Previous Entry Share Next Entry
vinxru

Компилятор ассемблера для БК0010

Захотелось мне написать какую нибудь программу для БК0010 на ассемблере. Я два дня искал ассемблер PDP-11, который бы смог создать двоичный образ для эмулятора БК0010. И не нашел. :( Поэтому я решил написать компилятор ассемблера сам. Заодно и ассемблер выучу. До сегодняшнего дня, я ведь о нем вообще ничего не знал.

Компилятор я написал всего за 2 часа. PDP-11 действительно простой ассемблер. И написал простую демку.

(Надпись двигается вверх-вниз)


Под катом моя программа и кусок компилятора (самый важный).


Программ для БК
        ORG 01000
START:  MOV     #040000, R3
LOOP0:	MOV     #185, R4    
LOOP1:  JSR 	R5, @#DRAW
        ADD     #64, R3
	SOB	R4, LOOP1
	MOV     #185, R4    
LOOP2:  SUB     #64, R3
	JSR 	R5, @#DRAW
        SOB	R4, LOOP2
	BR	LOOP0
;-----------------------------------------------
DRAW:   MOV	#BMP, R0
	MOV	R3, R1
        MOV     #568, R2
LOOP3:  MOV     (R0)+, (R1)+
	MOV     (R0)+, (R1)+
	MOV     (R0)+, (R1)+
	MOV     (R0)+, (R1)+
	SOB	R2, LOOP3
	RTS	R5
;-----------------------------------------------
BMP:    insert_file "img.bin", 0, 4544
;-----------------------------------------------
END:    make_bk0010_rom "test.bin", START, END

Стянуть бинарник http://rghost.ru/36818139

Кусок компилятора:
struct Arg {
  int ext, code;
  bool needExt;
};

struct SimpleCommand {
  const char* name;
  int code;
};

struct ImmCommand {
  const char* name;
  int code, max;
};

int readReg() {
  static const char* regs[] = { "R0","R1","R2","R3","R4","R5","SP","PC",0 };
  return p.needToken(regs);
}

bool readAddr() {
  int n;
  if(p.ifToken(labelName, n)) { p.bufInt=labelOff[n]; return true; }
  if(p.ifToken(ttString1)) { p.bufInt = p.buf[0]; return true; }
  return p.ifToken(ttInteger);
}

void readArg(Arg& a) {
  int mode, reg;
  bool x = p.ifToken("@");
  bool n = p.ifToken("#");
  if(readAddr()) {
    a.ext = p.bufInt;
    a.needExt = true;
    if(!n && p.ifToken("(")) {
      mode = 6;
      reg = readReg();
      p.needToken(")");
    } else {
      reg = 7;
      mode = n ? 2 : 6;
    }
    if(x) mode++;
    a.code = (mode<<3) | reg;
    return;
  }
  if(n) p.syntaxError();
  bool d = p.ifToken("-");
  a.needExt = false;
  if(!d) {
    if(readAddr())
      a.needExt=true, a.ext=p.bufInt;
  }
  bool o = p.ifToken("("); if((x || d || a.needExt) && !o) p.needToken("(");  
  reg = readReg();
  if(o) p.needToken(")");
  bool i = false;
  if(o && (!d && !a.needExt)) i = p.ifToken("+");
  if(x && !d && !i && !a.needExt) { a.needExt=true; a.ext=0; }
  mode = !o ? 0 : i ? 2 : d ? 4 : a.needExt ? 6 : 1;
  if(x) mode++;
  a.code = (mode<<3) | reg;
}

void compileCpuCommand() {
  // Комманды без аргументов

  static SimpleCommand simpleCommands[] = {
    "halt", 0, "wait", 1, "rti", 2, "bpt", 3, "iot", 4, "reset", 5, "rtt", 6, "nop", 0240,
    "clc", 0241, "clv", 0242, "clz", 0244, "cln", 0250, "sec", 0261, "sev", 0262, 
    "sez", 0264, "sen", 0270, "scc", 0277, "ccc", 0257, 0
  };

  if(p.ifToken(simpleCommands, n)) {
    write(simpleCommands[n].code);
    return;
  }

  // Комманды с одним регистром

  static SimpleCommand oneCommands[] = {
    "jmp", 00001, "swab", 00003,
    "clr", 00050, "clrb", 01050, "com",  00051, "comb", 01051, 
    "inc", 00052, "incb", 01052, "dec",  00053, "decb", 01053, 
    "neg", 00054, "negb", 01054, "adc",  00055, "adcb", 01055, 
    "sbc", 00056, "sbcb", 01056, "tst",  00057, "tstb", 01057, 
    "ror", 00060, "rorb", 01060, "rol",  00061, "rolb", 01061, 
    "asr", 00062, "asrb", 01062, "asl",  00063, "aslb", 01063, 
    "sxt", 00067, "mtps", 01064, "mfps", 01067, 0
  };

  if(p.ifToken(oneCommands, n)) {
    Arg a;
    readArg(a);
    write((oneCommands[n].code<<6)|a.code);
    if(a.needExt) write(a.ext);
    return;
  }

  // Комманды перехода
  
  static SimpleCommand jmpCommands[] = { 
    "br",  00004, "bne",  00010, "beq", 00014, "bge", 00020, "blt", 00024, 
    "bgt", 00030, "ble",  00034, "bpl", 01000, "bmi", 01004, "bhi", 01010, 
    "bvc", 01024, "bhis", 01030, "bcc", 01030, "blo", 01034, "bcs", 01034,
    "blos", 01014, 
    0 
  };

  if(p.ifToken(jmpCommands, n)) {
    int i = needAddr();
    i-=writePos+2;
    if(i&1) p.syntaxError("unaligned");
    i/=2;
    if(step2 && (i<-128 || i>127)) p.syntaxError();
    write((jmpCommands[n].code<<6) | (i&0xFF));
    return;
  }

  // Комманды с константой
  
  static ImmCommand immCommands[] = {
    "emt", 0104000, 0377, "trap", 104400, 0377, "mark", 0006400, 077, 0
  };

  if(p.ifToken(immCommands, n)) {
    int i = p.needInteger();
    if(i<0 || i>immCommands[n].max) p.syntaxError();
    write(immCommands[n].code | i);
    return;
  }

  // Комманды с двумя регистрами

  static const char* twoCommands[] = { 
    "", "mov", "cmp", "bit", "bic", "bis", "add", "", "",
    "movb", "cmpb", "bitb", "bicb", "bisb", "sub", 0
  };

  if(p.ifToken(twoCommands, n)) {
    Arg src, dest;
    readArg(src);
    p.needToken(",");
    readArg(dest);
    write((n<<12)|(src.code<<6)|dest.code);
    if(src.needExt) write(src.ext);
    if(dest.needExt) write(dest.ext);
    return;
  }

  // Остальные команды
  
  if(p.ifToken("jsr")) {
    int r = readReg();
    p.needToken(",");
    Arg a;
    readArg(a);
    write(004000 | (r<<6) | a.code);
    if(a.needExt) write(a.ext);
    return;
  }

  if(p.ifToken("sob")) {
    int r = readReg();
    p.needToken(",");
    int n = (writePos + 2) - needAddr();
    if(n&1) p.syntaxError();
    n/=2;
    if(n<0 || n>63) p.syntaxError();
    write(0077000 | (r<<6) | (n&077));
    return;
  }

  if(p.ifToken("rts")) {
    int r = readReg();
    write(0000200 | r);
    return;
  }

  p.syntaxError();
}

(В этом коде обязаны быть ошибки. В некоторые моменты PDD11 я еще не въехал.)

Ностальгия. Я на ассемблере писал программу на Z80 и известном в начале 90-х компьютере ZX-Spectrum. Причем эта программа была коммерческой, так как за неё мне очень хорошо заплатили. Программа управляла сценой и цветными лампочками, в первом варьете в нашем городе. Круто на то время это все было. После этого ассемблер стал моим любимым языком, хотя он и сложный сам по себе. :)

Обалдеть! Вот это я понимаю, есть что вспомнить, это не какой там нибудь "Приветь мирЬ!" ;))))

Да, очень хороший опыт в моей молодости с точки зрения программирования. :)))

Я до сих пор помню код RET :) Друга как-то спросил, помнишь мол? Отвечает - 201! :)
Тяжело мне давались только процедурки на прерывании IM2. А на 128k ОЗУ впервые понял как работает страничная адресация (после 49152 адреса были страницы, если не ошибаюсь).

Edited at 2012-03-03 02:02 pm (UTC)

Я честно говоря помню только команды ассемблера. Пришлось сыну помогать в учебе в университете. А так уже все забыл. :)

Я дак всегда в 16-ричной системе работал. 49152 = С000h

Ого! Респект и уважуха. Я только на z80 на асме кодил и то это было давно.

Edited at 2012-03-03 06:13 am (UTC)

А я сейчас ради изучения и развлечения, пишу мелкие программки для всех старых компьютеров. Наиболее мозголомное программирование, это писать игры для Atari 2600 (там 128 байт ОЗУ, процессор 6502 и почти программное формирование видео сигнала).

писал диплом на ассемблере)
PS заведите себе для расшаривания и хранения файлов dropbox. рекомендую.

Зарегистрируйтесь тогда по моему приглашению пожалуйста http://db.tt/6OeRp4gv
Получите на 250Мб больше.

Однозначно Круто! ;)))

Круто будет, если я какую нибудь игрушку перепишу на БК. Но вот какую, я еще не решил.

Дружище, ты просто м0ньяк программер (сказано с уважением)! ;)))))

по ассамблеру одна из лучших книг Питер Абель Ассемблер для начинающих

Спасибо, только я уже заканчивающий. :) Ваша книга для процессоров x86, а тут процессоры pdp-11.

преобразавать Ассемблер можно на любой проц и любую структуру

Вряд ли можно понять, читая справку по X86, что делает команда: JSR R3, @(SP)+. Или что значит последовательность @# в команде JSR PC, @#123

Но самое необычное, что можно записывать данные к константы.

MOV #12, R0 // Записать число 12 в регистр R0
MOV #12, #4 // Записать число 12 в число 4

ну понятное что каманды ращщитаные под внутренности кампа нельзя использовать польностью в обрезанных устроиствах,
это и есть теория ограниченного применения

Edited at 2012-03-03 02:53 pm (UTC)

Это стандартные (базовые) команды процессора.

хм моэжеть это и легенда но погаваривають
что унаших коопий амереканских чипов врали и они
хотя такого даже я не встречал

Что то я тебя плохо понимаю.

Есть такая легенда что когда выберали между нашими чипами и покупкой амереканских представителям полютберо подсунули наши чипы у которых врали даже базовые каманды,их даже программировать было невозможно,
таким образом вместо разработки наших моделей начели повальное капирование западных аналогов,
Я не знаю правда это или нет ,Но легенда красивая

Какими, простите, чипами? Вы вообще о каких конкретно компьютерах говорите? Что-то Ваши слова без подтверждений на сказки похожи.

Это Легенда расказанная мне одним из старейших работников ОДесского института связи,подробностей не знаю,но действительно у нас ставили устаревшие копий западных сисетем

читать справки дело неблагодарное:)))они часто вруть

Да вообще-то ничего необычного нет.

MOV #12, #4
фактически представляется как
MOV (R7)+, (R7)+
.#12
.#4

команда возьмет число из ячейки с адресом в R7 (это будет 12), инкрементировав R7 и положит в ячейку с адресом R7 (ячейка со значением 4) и снова инкрементирует R7. Фактически - пример самомодифицирующегося кода.

Слава богу ваши статьи не пропали, видимо это был глюк с правами доступа и видимости у ливжорнала :)

Меня очень интересует этот ваш компилятор, он есть в каком нибудь "релизном" варианте?

You are viewing vinxru