
Рыжие ячейки - куда можно было бы впихнуть нужные мне CMP и UDIV2. Красная - где команда с "побочным эффектом", из-за чего хоть назвать её осмысленно сложно. Серые - все остальные "недокументированные".
Как видно, кроме обычного взятия модуля, мы могли бы делать "взятие модуля с накоплением", т.е
Acc = Acc + ABS(DataBus)
для команды ABSA,
Acc = Acc - ABS(DataBus)
для команды ABSS,
Acc = Acc ± ABS(DataBus)
для команды ABSPM (знак "+", если однобитный регистр Inv=0, знак "-" если Inv=1)
Как-то всё-таки суммировать модули - занятие специфическое.
Следующая строка - единственная, команды из которой выполняются за 1 такт. Две команды есть - ZAcc (инициализировать аккумулятор одной из 4 "длинных" констант) и C (загрузить данные в регистр C). И что-то ещё придумать сложно - ну разве что загрузить что-то во флаг S, что было бы чрезвычайно необходимо при наличии немаскируемых прерываний, чтобы можно было в любой точке выполнения программы запомнить все регистры и затем вернуть В ТОЧНОСТИ как было. Но у нас пока вообще прерываний нет.
Мы не стали до конца декодировать команду C, поэтому она сожрала 4 соседних квадрата. Два из них - совсем идентичны, можно пользоваться любым.
И ещё одна команда - NOP (No OPeration), "ничего не делать". Пока что в ней нет особого смысла - у нас таких NOP 128 штук, все адреса от 0 до 127. По шине SrcAddr это - непосредственные значения, Imm (Immediate), абсолютно необходимая штука. А по DestAddr места пока что пустуют. Можно было бы сделать прямую адресацию к памяти "на запись", скоро пойдёт код, где очень хочется, чтобы такая адресация была! И если так, то для единообразия можно и нулевой адрес сделать совершенно законным, а NOP будет прерогативой АЛУ :)
Далее мы видим дополнительные команды деления на два, "деление с накоплением", т.е
Acc = Acc + DataBus/2 (команда DIV2A), Acc = Acc - DataBus/2 (команда DIV2S), Acc = Acc ± DataBus/2 (команда DIV2PM)
но первые две из них имеют "побочный эффект" - данные с DataBus также поступают в регистр C.
С этим "побочным эффектом" можно справиться, если для команды "C" декодировать хотя бы ещё один бит, это прибавляет 1 лишний ЛЭ к АЛУ. Но даже без него, мне эти команды пока не нужны.
Мне нужна команда CMP (CoMPare, сравнить). Это как SUB (Subtract, вычесть), но результат вычитания не заносится в Acc, всё что мы получаем - это флаг S (sign), чтобы затем совершить условный переход. Хотя, как это ни странно, у нас есть ровно одно место, где эта команда укоротила бы программу на 1 слово, в FindMDD3:
SUB [SP+1] ;можно и "пожертвовать" значением в Acc, ;т.к в [SP] лежит точно такое же! JL @@skip ;дистанция оказалась больше - надо обновить максимум и его индекс ;[SP+1] [SP] ;двухпортовая память-это зашибись! ;но мы ради упрощения модуля памяти лишились этой возможности ;в этом месте заведомо i=k=0 C [SP] [SP+1] C
Как видно, у нас одно и то же значение лежало как в Acc, так и в [SP]. Сравнили, решили обновить максимум, лежащий в [SP+1] - и вынуждены были работать через регистр C, так как напрямую переправить из памяти в память сейчас нельзя. А вот был бы CMP вместо SUB - сразу из аккумулятора и положили бы!
При сортировке у нас в аккумуляторе вычисляется векторное произведение - оно нам нафиг не сдалось, только его знак. При вычислении Чебышевской метрики тоже, как ни странно, замена SUB на CMP выигрыша не даёт пока что.
И ещё одна команда, которую можно было бы вмонстрячить - это UDIV2, беззнаковое деление на 2. Также меня устроит команда
Acc = Acc - DataBus SHR 1 (логический сдвиг вправо, он же "беззнаковый")
потому что если в качестве DataBus подсунуть Acc, то получим то же самое более-менее. Поэтому и запихнул её в данную ячейку - тогда всё что нужно - это подкрутить выражение
assign BSigned = (DestAddr[3:2] != 2'b10);
чтобы добавить эту конкретную ячейку, всё остальное уже выполняется как надо.
Это мне сэкономит пока что 2 слова данных и 1 слово памяти.
Дело в том, что я сначала двигаю масштаб влево (умножаю на 2), до тех пор, пока не будет переполнения. А потом надо "отыграть назад", но переполненное значение нужно воспринимать как беззнаковое. Если есть такая команда, то всё делается в одну строчку:
UDIV2 Acc
А если использовать обычный DIV2, то появится лишняя единица в старшем разряде (арифм. сдвиг вправо вместо логического), и нужно будет её оттуда выкинуть, видимо прибавив 0x8000. Но это значение я не могу ввести напрямую - оно должно храниться в памяти, и получится как-то так:
DIV2 Acc X MinusOne ADD [X+k]
Понятное дело, это не все команды, которые мне хотелось бы иметь, это лишь те, которые достаточно легко сюда вмонстрячиваются. Когда-то думал, что будет ещё команда MAX (если значение на шине данных больше, чем в аккумуляторе, заносим его в аккумулятор), но она в общую логику совсем не вписывалась...
Но даже эти две в каком-то смысле нарушат логическую структуру АЛУ, хотя и делают его более мощным :)
Стоит ли добавить команды CMP и UDIV2
Да!
1(25.0%)
Добавить CMP
0(0.0%)
Добавить UDIV2
0(0.0%)
Сначала программу дописать, если чуть-чуть не влезет - добавить
3(75.0%)
Нет.
0(0.0%)