|
|
  |
Свои процессоры, Разработка своих процессоров со своей системой команд |
|
|
|
Jun 1 2010, 05:56
|
Участник

Группа: Участник
Сообщений: 72
Регистрация: 26-05-05
Пользователь №: 5 422

|
Цитата(Leka @ Jun 1 2010, 02:17)  Нужна еще память данных для массивов, косвенно адресуемых LOAD/STORE. На днях сделаю. Цитата(des00 @ May 30 2010, 14:32)  Спасибо конечно, но вот те кто не пользуются альедеком должны вытаскивать структуру из скомпилированного bdf файла? Это я к тому что структурная и функциональная схема не помешали бы, также как и описание портов ввода/вывода процессора %) Учту.
|
|
|
|
|
Jun 1 2010, 22:29
|
Профессионал
    
Группа: Участник
Сообщений: 1 075
Регистрация: 30-09-05
Пользователь №: 9 118

|
Чтобы проще было вылавливать ошибки в компиляторе с "ассемблерного" подмножества Си, решил добавить промежуточный уровень "машинного" подмножества Си: ... --> "ассемблерный" Си --> "машинный" Си --> машинные коды. Пример: N-ферзей на "машинном" Си для 3х-операндной архитектуры без типов, main() - тестовая программа на Си - игноируется компилятором в машинные коды по пробелу в начале строки. CODE 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); } }
Сообщение отредактировал Omen_13 - Jul 18 2010, 20:56
Причина редактирования: Оформление кода
|
|
|
|
|
Jun 2 2010, 06:50
|
Участник

Группа: Участник
Сообщений: 72
Регистрация: 26-05-05
Пользователь №: 5 422

|
А что означают выражения?: R6[R10]=R7; R13=R3[R10];
Николай.
|
|
|
|
|
Jun 2 2010, 10:31
|
Профессионал
    
Группа: Участник
Сообщений: 1 075
Регистрация: 30-09-05
Пользователь №: 9 118

|
Косвенную адресацию памяти 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(){}). CODE 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)); } }
Сообщение отредактировал Omen_13 - Jul 18 2010, 20:57
Причина редактирования: Оформление кода
|
|
|
|
|
Jun 2 2010, 19:34
|
Участник

Группа: Участник
Сообщений: 72
Регистрация: 26-05-05
Пользователь №: 5 422

|
Закончил "в черне" процессор. Вынес память программ и данных из ядра. Дополнил системной шиной AMBA AHB и отладочными блоками для работы через JTAG. Теперь только тесты, тесты, правка и еще раз тесты. Описание дополню в выходные. Николай.
Прикрепленные файлы
rf32.rar ( 447.89 килобайт )
Кол-во скачиваний: 82
|
|
|
|
|
Jun 5 2010, 16:47
|
Участник

Группа: Участник
Сообщений: 72
Регистрация: 26-05-05
Пользователь №: 5 422

|
Цитата(Ynicky @ Jun 2 2010, 23:34)  Описание дополню в выходные. Дополнил описание.
|
|
|
|
|
Jun 7 2010, 19:40
|
Профессионал
    
Группа: Участник
Сообщений: 1 075
Регистрация: 30-09-05
Пользователь №: 9 118

|
Первая версия компилятора "ассемблерный" Си --> "машинный" Си. Поддерживаются: 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(указателя на кадр) - как в подпрограммах получать доступ к глобальным переменным в регистровом файле?
|
|
|
|
|
Jun 7 2010, 21:25
|
Профессионал
    
Группа: Участник
Сообщений: 1 075
Регистрация: 30-09-05
Пользователь №: 9 118

|
У меня указатель на область локальных переменных аппаратно "разворачивал" нумерацию регистров, так что 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; ... } С программной точки зрения подобная перенумерация регистров очень удобна. Проверил и в железе, и в ассемблере. Единственный недостаток - лишняя ступень логики.
|
|
|
|
|
Jun 8 2010, 06:39
|
Участник

Группа: Участник
Сообщений: 72
Регистрация: 26-05-05
Пользователь №: 5 422

|
Цитата(Leka @ Jun 7 2010, 23:40)  как в подпрограммах получать доступ к глобальным переменным в регистровом файле? Тут я не понял. Я всегда считал, что глобальные переменные находятся в памяти данных. И доступ к ним осуществляется через load/store. Если они будут находиться в регистровом файле, тогда без переключения регистров не обойтись. И сколько их может потребоваться? Николай. P.S. Предлагаю пока не заморачиваться по поводу FP. А дальше будет видно.
Сообщение отредактировал Ynicky - Jun 8 2010, 07:17
|
|
|
|
|
Jun 8 2010, 08:21
|
Профессионал
    
Группа: Участник
Сообщений: 1 075
Регистрация: 30-09-05
Пользователь №: 9 118

|
Для вспомогательной подпрограммы основные данные - внешние, "в противном случае зовется ... иначе" - задача. Локальных по своей сути данных немного, это промежуточные результаты выражений, счетчики циклов, и тп. Нет никакого смысла делать большой регистровый файл для локальных данных: 16 уровней вложенности пп * 4 локальные переменные в среднем = 64 регистра. Если основные данные не в регистровом файле, имеет смысл отказаться от load/store архитектуры, добавив косвенно-регистровую адресацию ( *a=*b+*c; if(*a==*d)...; и тп ). Была у меня такая в железе, см ветку "посоветуйте простой софт-процессор". Цитата Предлагаю пока не заморачиваться по поводу FP. Согласен, сначала нужен компилятор "машинный" Си --> машинные коды.
Сообщение отредактировал Leka - Jun 8 2010, 08:25
|
|
|
|
|
Jun 9 2010, 09:55
|
Участник

Группа: Участник
Сообщений: 72
Регистрация: 26-05-05
Пользователь №: 5 422

|
To Leka: Попробовал написать простенький тест. После компиляции a2m запустил LCC. Пока 2 явных замечания: 1. return надо отделить от 1 и 0. 2. в разных подпрограммах повторяющиеся метки. Проект во вложении. Николай.
|
|
|
|
|
Jun 9 2010, 12:52
|
Профессионал
    
Группа: Участник
Сообщений: 1 075
Регистрация: 30-09-05
Пользователь №: 9 118

|
Цитата 1. return надо отделить от 1 и 0. Забыл написать, надо "return(1);" вместо "return 1;" Сделано специально - как вызов функции, а не ключевое слово. Цитата 2. в разных подпрограммах повторяющиеся метки. Вроде это не противоречит стандарту (локальность меток в пределах функции), но если надо - могу добавлять имя функции к метке.
|
|
|
|
|
  |
8 чел. читают эту тему (гостей: 8, скрытых пользователей: 0)
Пользователей: 0
|
|
|