Первый шаг к этому - научиться ставить запятую между любыми десятичными разрядами. Это было бы предельно просто, используй мы в любом случае 5 цифр, но более заковыристо, если мы не хотим лишних нулей, однако обязаны их поставить перед запятой и после запятой.
Настолько заковыристо, что добавляет нашей процедуре ещё 4 слова (8 байт), а потом ещё 2 слова, чтобы чуть высвободить регистры, итого укладываемся ровно в 30 слов (60 байт), при этом новая процедура может и не рисовать запятую вовсе, т.е держать и старую, и новую нам не требуется. Любой каприз (со знаком, без знака, запятую ставить, и если ставить, то где) - всё здесь, в 30 словах :)

Вот он, код:
;отобразить число со знаком из ACC, причём поставить запятую в позицию, заданную в регистре i. ;меняет регистры k,Y,Acc ;(j мы сохраняем в стек, чтобы вернуть как было) ;после выполнения k=0 SignedFixed proc SUB 0 JGE UnsignedFixed UART0 '-' ABS Acc SignedFixed endp UnsignedFixed proc [SP++] j k 4 ;номер обрабатываемого разряда [SP+1] -1 ;-1 означает, что значащих цифр ещё не было, 0-что появились Y BCDtable @@start: JNik @@skipP0 ;уже здесь нужно проверить на запятую, поскольку её наличие заставит поставить нолик! [SP+1] 0 ;указали на значимость :) @@skipP0: j [SP+1] @@sub: SUB [Y+k] j++ 0 JGE @@sub ADD [Y+k] jLOOP @@proceed ;прыжка не будет, если [SP+1]=-1 и текущий разряд нулевой kloop @@start [SP+1] 0 @@proceed: [SP] Acc ;сейчас аккумулятор пригодится... Acc '0' ADD j SUB [SP+1] UART0 Acc [SP+1] 0 Acc [SP] JNik @@finish UART0 ',' @@finish: kloop @@start j [--SP] JMP [--SP] UnsignedFixed endp
Чтобы эта штука заработала, мы ввели новую, недостающую команду в QuatCore: JNik (Jump if Not i=k). У нас была "непарная" Jik (Jump if i=k), и свободная ячейка, которая ждала своего часа:

Три соседа что-то делают, но я пока не вполне разбирался, что именно :) Дело в том, что инкременты i++, j++, k++ реализованы немножко "лениво", не проверяя DestAddr[3], и циклы тоже сделаны "лениво", не проверяя DestAddr[2], в итоге мы получим некую комбинацию циклов и инкремента, но кто кого пересилит - нужно разбираться. Может, даже что-то полезное из этого выйдет. А вот четвёртая ячейка вполне нас устраивает, ячейка ijk безобидная, тем более что мы её ещё ни разу не включали (у нас есть параметр ijkEnabled, выставив ноль мы отключаем логику, отвечающую за команды ijk в Src и Dest и экономим 24 ЛЭ, но заносить все-все индексные регистры в стек, когда припрёт, будет тем ещё геморроем)
Чтобы добавить команду JNik, мы поменяли строку в модуле QuatCorePCrelJumpDecision. Было так:
wire DoJik = isLOOP & (DestAddr[1:0] == 2'b11) & iEQk;
а стало так:
wire DoJik = isLOOP & (DestAddr[1:0] == 2'b11) & (iEQk ^ DestAddr[2]);
Как результат, процессор "растолстел" на 1 ЛЭ, в текущих настройках - от 482 ЛЭ до 483 ЛЭ (сюда же входит и мигающий с частотой 1 Гц светодиод, который нас успокаивает). Не страшно.
Изначально команда Jik вводилась для работы с треугольными и симметричными матрицами, и пока дожидается своего часа.
Смысл такой: в регистре i мы задаём позицию запятой, причём позиция отсчитывается так:
4,3210
где запятая находится сейчас - это позиция 4.
Итак, регистр i может принимать любое значение. От 0 до 4 означает, что мы поставим запятую в нужном месте, от 5 и выше - запятой попросту не будет.
Когда мы начинаем обрабатывать очередной разряд (метка @@start:), первым же делом проверяем - не тот ли это разряд, где стоит запятая? И если это он, то объявляем его "значащим", т.е даже если там ноль, он всё равно отобразится.
Теперь мы точно знаем, что на данной итерации дойдём до метки @@proceed: и отобразим цифру, стоящую перед запятой. Далее повторно проверяем позицию - и отображаем саму запятую. Вот, собственно, и вся хитрость. Добавилось два условных перехода и две команды - объявить цифру "значащей" и непосредственно нарисовать запятую. Ах да, ещё у нас регистр i сменился на j (поскольку i занят), но теперь и цикл в процедуре main организовывать стало не на чем, поэтому мы всё-таки добавили [SP++] j в начале процедуры (занести значение в стек) и j [--SP] в конце (вытолкнуть из стека).
Вот тестовая программа:
.rodata OurString Int16 'С','т','е','п','е','н','и',' ','м','и','н','у','с',' ','д','в','о','й','к','и',':',13,10,-32768 ZeroStr Int16 13,10,'Н','о','л','и','к',':' CRLF Int16 13,10,-32768 BCDtable dw 1,10,100,1000,10000 MinusOne Int16 -32768 .data Stack dw ?,?,?,? .code main proc SP Stack Z MinusOne i 5 @@outer: X OurString CALL print j 15 ACC 1 @@start: C Acc CALL SignedFixed ;очередное число UART0 9 Acc C C [Z+k] MUL Acc DIV2S 1 ADD Acc ;сделали умножение на -2 в итоге... jLOOP @@start X ZeroStr CALL print Acc 0 CALL SignedFixed ;хотим проверить, "голый" ноль вообще отобразится? UART0 13 ;CR UART0 10 ;LF iLOOP @@outer @@endless: JMP @@endless main endp ;X указывает на начало строки текста ;конец обозначается отрицательным числом (у нас НЕТ ФЛАГА НУЛЯ!!!) ;меняет значение Acc, остальные регистры остаются как есть print proc [SP++] i i 0 @@start: ABS [X+i] ;хитрая проверка на -32768 JO @@finish UART0 Acc i++ 0 JMP @@start @@finish: i [--SP] JMP [--SP] print endp
Поскольку теперь мы используем 2 индексных регистра в основной программе, а третий ожидаем нулевым после вызова всех процедур, то мы сделали print более аккуратным. Также мы догадались, что перенос строки выводить удобнее "ручками", чем вызывать целый print, а уж один символ табуляции - тем более.
Мы рисуем одну и ту же числовую последовательность, но с разным расположением запятой. Сначала её вообще нет (позиция 5), затем мы делаем 4 знака после запятой, 3 знака и т.д.
Я вижу одну проблему: ноль "с фиксированной запятой". Мы неявно полагаем, что после запятой рано или поздно должны появиться значащие разряды, поэтому рисуем ноль перед запятой, затем запятую, затем ещё нули - и вдруг оказывается, что там и нет ничего. Возможно, что вместо
0,0000 нам следовало бы выдавать просто 0.
Чтобы этого достичь, нам нужно теперь уже в наиболее явном виде рассмотреть отдельный случай нуля, и если это он - выдать 0 и побыстрее вернуться! Правда, проверки на равенство как таковой у нас нет (как и флага нуля, вот это совпадение :)), для работы с зашумлёнными "реальными данными" она не так уж нужна. Её можно "эмулировать", взяв модуль разности и вычитая единичку. Если результат отрицательный - значит равны! Но возможно, это и перебор, меня и так устраивает.
Как должен отображаться ноль в числах с фикс. запятой?
0
5(71.4%)
0,0000 (повторяя количество разрядов после запятой)
2(28.6%)