Leka 1 31 мая, 2010 Опубликовано 31 мая, 2010 (изменено) · Жалоба На этой неделе постараюсь выложить первую версию компилятора. Отвлекают вопросы методического характера, например: Си ориентирован на явное использование указателей --> получается неудобно для архитектуры с большим регистровым файлом, тк указатели нельзя применять к регистрам... Память программ и регистровый файл Нужна еще память данных для массивов, косвенно адресуемых LOAD/STORE. Изменено 31 мая, 2010 пользователем Leka Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Ynicky 0 1 июня, 2010 Опубликовано 1 июня, 2010 · Жалоба Нужна еще память данных для массивов, косвенно адресуемых LOAD/STORE. На днях сделаю. Спасибо конечно, но вот те кто не пользуются альедеком должны вытаскивать структуру из скомпилированного bdf файла? Это я к тому что структурная и функциональная схема не помешали бы, также как и описание портов ввода/вывода процессора %) Учту. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Leka 1 1 июня, 2010 Опубликовано 1 июня, 2010 (изменено) · Жалоба Чтобы проще было вылавливать ошибки в компиляторе с "ассемблерного" подмножества Си, решил добавить промежуточный уровень "машинного" подмножества Си: ... --> "ассемблерный" Си --> "машинный" Си --> машинные коды. Пример: N-ферзей на "машинном" Си для 3х-операндной архитектуры без типов, main() - тестовая программа на Си - игноируется компилятором в машинные коды по пробелу в начале строки. R1; R2; R3[20]; R4[20]; R5[20]; R6[20]; R7; R8; R9; R10; R11; R12; R13; R14; queens(){ L1:R2=0; L2:R12=R1&1; L3:R13=1<<R1; L4:R9=R13-1; L5:R13=R1>>1; L6:R7=R9>>R13; L7:R3[1]=0; L8:R4[1]=0; L9:R5[1]=0; L10:R6[1]=R7; L11:R10=1; L12:if(R7==0)goto L46; L13:R13=0-R7; L14:R8=R7&R13; L15:R13=-1-R8; L16:R7=R7&R13; L17:if(R10!=R12)goto L20; L18:if(R7!=0)goto L20; L19:R2=R2<<1; L20:if(R10==R1)goto L44; L21:R11=R10+1; L22:R6[R10]=R7; L23:R13=R3[R10]; L24:R13=R13|R8; L25:R3[R11]=R13; L26:R13=R4[R10]; L27:R13=R13|R8; L28:R13=R13<<1; L29:R4[R11]=R13; L30:R13=R5[R10]; L31:R13=R13|R8; L32:R13=R13>>1; L33:R5[R11]=R13; L34:R13=R3[R11]; L35:R14=R4[R11]; L36:R13=R13|R14; L37:R14=R5[R11]; L38:R13=R13|R14; L39:R13=-1-R13; L40:R13=R13&R9; L41:R7=R13; L42:R10=R11; L43:goto L45; L44:R2=R2+1; L45:goto L48; L46:R10=R10-1; L47:R7=R6[R10]; L48:if(R10!=0)goto L12; L49:if(R12!=0)goto L51; L50:R2=R2<<1; L51:return(R2); } main(){ int n,cnt; for(n = 1; n < 15; n = n + 1){ R1= n; queens(); cnt = R2; printf("queens(%d)=%d \n", n, cnt); } } Изменено 18 июля, 2010 пользователем Omen_13 Оформление кода Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Ynicky 0 2 июня, 2010 Опубликовано 2 июня, 2010 · Жалоба А что означают выражения?: R6[R10]=R7; R13=R3[R10]; Николай. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Leka 1 2 июня, 2010 Опубликовано 2 июня, 2010 (изменено) · Жалоба Косвенную адресацию памяти R6[R10]=R7; --> STORE R7,(R6+R10) R13=R3[R10]; --> LOAD R13,(R3+R10) Для 2х-операндной архитектуры: R6[R10]=R7; --> MOV R0,R6 ADD R0,R10 ST R7,(R0) R13=R3[R10]; --> MOV R0,R3 ADD R0,R10 LD R13,(R0) или переписать "ассемблерный" код под 2х-операндную архитектуру с использованием указателей R6 R3 вместо пар база-индекс: *R6=R7; R13=*R3; и учесть такие мнемоники в трансляторе в машинные коды. Вариант N-ферзей с указателями на "ассемблерном" Си (кроме main(){}). queens( int N ){ int count, arow[20], aleft[20], aright[20], aposs[20], poss, place, val, pos, pos1, N1, temp, temp1, *prow, *pleft, *pright, *pposs, *prow1, *pleft1, *pright1, *pposs1; count = 0; N1= N & 1; temp = 1 << N; val = temp - 1; temp = N >> 1; poss = val >> temp; pos = 1; // prow=arow+1; pleft=aleft+1; pright=aright+1; pposs=aposs+1; //arow[1] = 0; //aleft[1] = 0; //aright[1] = 0; //aposs[1] = poss; *prow = 0; *pleft = 0; *pright = 0; *pposs = poss; do{ if( poss != 0 ){ temp = -poss; place = poss & temp; temp = ~place; poss = poss & temp; if( pos == N1 && poss == 0 ) count = count << 1; if( pos != N ){ pos1 = pos + 1; // prow1 = prow+1; pleft1 = pleft+1; pright1 = pright+1; pposs1 = pposs+1; //aposs[pos] = poss; *pposs = poss; //temp = arow[pos]; temp = *prow; temp = temp | place; //arow[pos1] = temp; *prow1 = temp; //temp = aleft[pos]; temp = *pleft; temp = temp | place; temp = temp << 1; //aleft[pos1] = temp; *pleft1 = temp; //temp = aright[pos]; temp = *pright; temp = temp | place; temp = temp >> 1; //aright[pos1] = temp; *pright1 = temp; //temp = arow[pos1]; temp = *prow1; //temp1 = aleft[pos1]; temp1 = *pleft1; temp = temp | temp1; //temp1 = aright[pos1]; temp1 = *pright1; temp = temp | temp1; temp = ~temp; temp = temp & val; poss = temp; pos = pos1; // prow += 1; pleft += 1; pright += 1; pposs += 1; }else count = count + 1; }else{ pos = pos - 1; // prow -= 1; pleft -= 1; pright -= 1; pposs -= 1; //poss = aposs[pos]; poss = *pposs; } }while( pos != 0 ); if( N1 == 0 ) count = count << 1; return count; } main(){ int N; for(N = 1; N < 15; N = N + 1){ printf("queens(%d)=%d \n", N, queens(N)); } } Изменено 18 июля, 2010 пользователем Omen_13 Оформление кода Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Ynicky 0 2 июня, 2010 Опубликовано 2 июня, 2010 · Жалоба Закончил "в черне" процессор. Вынес память программ и данных из ядра. Дополнил системной шиной AMBA AHB и отладочными блоками для работы через JTAG. Теперь только тесты, тесты, правка и еще раз тесты. Описание дополню в выходные. Николай. rf32.rar Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Leka 1 2 июня, 2010 Опубликовано 2 июня, 2010 · Жалоба Написал компилятор "ассемблерный" Си --> "машинный" Си, причешу - выложу (либо завтра, если успею, либо в понедельник). Надо-бы побольше программ на "ассемблерном" Си для тестирования (как компилятора, так и процессора). "Машинный" Си --> машинные коды на этой неделе уже не успею, но эта задачка заметно проще. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Ynicky 0 5 июня, 2010 Опубликовано 5 июня, 2010 · Жалоба Описание дополню в выходные. Дополнил описание. to104rf32.pdf Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Leka 1 7 июня, 2010 Опубликовано 7 июня, 2010 · Жалоба Первая версия компилятора "ассемблерный" Си --> "машинный" Си. Поддерживаются: int, if-else, do-while, блоки { }, см. примеры N-ферзей. В текущей версии не поддерживаются вложенные круглые скобки и круглые скобки в выражениях. Запуск из командной строки: a2m < входной_файл > входной_файл Например(см. a.bat): a2m < q3.c > q3..c Выходные (и входные) файлы можно проверить любым Си-компилятором, например, Tiny C Compiler в скриптовом режиме: c:\tcc\tcc.exe -run q3..c При установленном TinyCC: a q3 Под "ассемблерным" подмножеством Си подразумевается отсутствие длинных арифметических и логических выражений, допускаются только 3х-операндные выражения(с учетом адреса перехода), которые м/б непосредственно преобразованы в машинные коды. По поводу FP(указателя на кадр) - как в подпрограммах получать доступ к глобальным переменным в регистровом файле? C.1.0.0.zip Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Leka 1 7 июня, 2010 Опубликовано 7 июня, 2010 · Жалоба У меня указатель на область локальных переменных аппаратно "разворачивал" нумерацию регистров, так что R(0), R(1), R(2), ... в подпрограмме любой вложенности указывали на глобальные переменные, а R(-1), R(-2), R(-3) - на локальные, или наоборот. Например, для 8 регистров: R0 R1 R2 R3 R4 R5 R6 R7 - int R0; R0 R7 R6 R5 R4 R3 R2 R1 - main(){ int R7, R6, R5; f1( R5 ); } R0 R1 R2 R7 R6 R5 R4 R3 - f1( int R7 ){ int R6, R5; f2( R5 ); } R0 R1 R2 R3 R4 R7 R6 R5 - f2( int R7 ){ int R6, R5; ... } С программной точки зрения подобная перенумерация регистров очень удобна. Проверил и в железе, и в ассемблере. Единственный недостаток - лишняя ступень логики. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Ynicky 0 8 июня, 2010 Опубликовано 8 июня, 2010 (изменено) · Жалоба как в подпрограммах получать доступ к глобальным переменным в регистровом файле? Тут я не понял. Я всегда считал, что глобальные переменные находятся в памяти данных. И доступ к ним осуществляется через load/store. Если они будут находиться в регистровом файле, тогда без переключения регистров не обойтись. И сколько их может потребоваться? Николай. P.S. Предлагаю пока не заморачиваться по поводу FP. А дальше будет видно. Изменено 8 июня, 2010 пользователем Ynicky Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Leka 1 8 июня, 2010 Опубликовано 8 июня, 2010 (изменено) · Жалоба Для вспомогательной подпрограммы основные данные - внешние, "в противном случае зовется ... иначе" - задача. Локальных по своей сути данных немного, это промежуточные результаты выражений, счетчики циклов, и тп. Нет никакого смысла делать большой регистровый файл для локальных данных: 16 уровней вложенности пп * 4 локальные переменные в среднем = 64 регистра. Если основные данные не в регистровом файле, имеет смысл отказаться от load/store архитектуры, добавив косвенно-регистровую адресацию ( *a=*b+*c; if(*a==*d)...; и тп ). Была у меня такая в железе, см ветку "посоветуйте простой софт-процессор". Предлагаю пока не заморачиваться по поводу FP. Согласен, сначала нужен компилятор "машинный" Си --> машинные коды. Изменено 8 июня, 2010 пользователем Leka Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Ynicky 0 9 июня, 2010 Опубликовано 9 июня, 2010 · Жалоба To Leka: Попробовал написать простенький тест. После компиляции a2m запустил LCC. Пока 2 явных замечания: 1. return надо отделить от 1 и 0. 2. в разных подпрограммах повторяющиеся метки. Проект во вложении. Николай. tst_jcc.rar Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Leka 1 9 июня, 2010 Опубликовано 9 июня, 2010 · Жалоба 1. return надо отделить от 1 и 0. Забыл написать, надо "return(1);" вместо "return 1;" Сделано специально - как вызов функции, а не ключевое слово. 2. в разных подпрограммах повторяющиеся метки. Вроде это не противоречит стандарту (локальность меток в пределах функции), но если надо - могу добавлять имя функции к метке. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Leka 1 9 июня, 2010 Опубликовано 9 июня, 2010 · Жалоба В a2m пока только один тип "int", поэтому "void" не допускается. Ошибки потом поправлю, сейчас прорабатываю компилятор в машинные коды. Из-за зависимости длины инструкции от данных (вставка imm20 и тп), решил поменять концепцию. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться