nabbla (nabbla1) wrote,
nabbla
nabbla1

Categories:

QuatCore: printf - числа со знаком

Выдавать "на терминал" (по UART) беззнаковые числа в десятичном виде мы научились, даже пропуская ненужные нули, и ушло на всё про всё 20 слов кода, или 40 байт.

Кстати, насчёт скорости работы этого примитивнейшего алгоритма. Дольше всего он обрабатывает разряд, если там девятка - производит аж 10 циклов, на что уходит 50 тактов. Далее, уходит ещё 14 тактов, прежде чем мы дойдём до команды UART0, и ещё 5 тактов после неё. Итого, 69 тактов. При тактовой частоте 4 МГц, это выходит 17,25 мкс, или частота выдачи: 58 кГц. Поскольку передатчик UART передаёт по сути 10 бит (стартовый, стоповый и 8 информационных), то на частоте до 580 000 бит/с мы затормаживать UART своим "медленным исполнением" точно не будем. Так, на 230 400 бод (как в прошлый раз) - точно никаких проблем, можно и 460 800 попробовать (это деление 4 МГц в 9 раз, точность 3,5% - ещё потянет), а вот 921600 уже перебор, но мы и частоту такую из 4 МГц нормально не получим. Питать UART от 80 МГц - это начнётся crossing clock domains, ну его нафиг... Мы никуда не торопимся.

Ещё 4 слова (8 байт) - и у нас будет универсальная процедура, которая умеет выводить также знаковые числа.





Вот код процедуры целиком, точнее, двух процедур, но "склеенных между собой":
	;в ACC лежит число со знаком, хотим его вывести в десятичной форме по UART0
	;используем регистры i, k, Y, Acc
	;в конце работы k=0
	SignedBin2Bcd proc
			SUB		0
			JGE		BetterBin2Bcd
			UART0		'-'
			ABS		Acc
	SignedBin2Bcd endp
	BetterBin2Bcd proc
			k		4	;номер обрабатываемого разряда
			[SP+1]		-1	;-1 означает, что значащих цифр ещё не было, 0-что появились
			Y		BCDtable
	@@start:	i		[SP+1]
	@@sub:		SUB		[Y+k]
			i++		0
			JGE		@@sub
			ADD		[Y+k]
			iLOOP		@@proceed	;прыжка не будет, если [SP+1]=-1 и текущий разряд нулевой
			kloop		@@start
			[SP+1]		0
	@@proceed:	[SP]		Acc		;сейчас аккумулятор пригодится...
			Acc		'0'
			ADD		i
			SUB		[SP+1]
			UART0		Acc
			[SP+1]		0
			Acc		[SP]
			kloop		@@start	
			JMP		[--SP]	
	BetterBin2Bcd endp


Мы можем вызывать BetterBin2Bcd, как и раньше, для беззнаковых чисел. А можем вызвать SignedBin2Bcd - тогда мы проверим знак числа, если это знак минус - выдадим по UART этот минус, в аккумулятор вместо самого числа поместим его модуль - и задача сведена к предыдущей :)

А вот выдать "степени минус двойки" оказалось на удивление нетривиальной задачей:

%include "Win1251.inc"
.rodata
	OurString Int16 'С','т','е','п','е','н','и',' ','м','и','н','у','с',' ','д','в','о','й','к','и',':',13,10,-32768
	ZeroStr Int16 'Н','о','л','и','к',':'
	CRLF Int16 13,10,-32768
	BCDtable dw 1,10,100,1000,10000
	MinusOne Int16 -32768
.data
	Stack	dw	?,?,?
.code
	main proc
				SP		Stack
				X		OurString
				Z		MinusOne
				CALL	 	print
				X		CRLF
				j		15
				ACC		1
		@@start:	C		Acc
				CALL		SignedBin2Bcd	;очередное число
				CALL		print	;перенос строки
				Acc		C
				C		[Z+k]
				MUL		Acc
				DIV2S		1
				ADD		Acc		;сделали умножение на -2 в итоге...
				jLOOP		@@start
				X		ZeroStr
				CALL		print
				Acc		0
				CALL		SignedBin2Bcd ;хотим проверить, "голый" ноль вообще отобразится?
		@@endless: 	JMP 		@@endless
	main endp


Не умещается у нас минус двойка в 16 бит, т.к для операций умножения (где положение "фиксированной точки" важно) мы воспринимаем их в диапазоне от -1 до 1-2-15. Поэтому мы сначала умножаем на -1, а потом удваиваем.

Но и здесь возникла подлянка: команда MUL (умножить) автоматом округляет нам число, а при попытке его удвоить срабатывает "байпас", в результате добавленная "половинка" уже становится целым и порождает нам совсем другую последовательность! Поэтому здесь мы вслед за MUL поставили команду DIV2S (вычесть из аккумулятора значение, делённое на два), чтобы избавится от ненужной половинки. Как ни странно, это помогло :)

Как видим по скриншоту в начале поста, оно заработало на ПЛИС, причём сейчас частоту UART поднял до 460 800 бит/с - и всё надёжно передаётся. Это не может не радовать.


А не такой уж этот процессор узкоспециализированный, как мне казалось :) Он не умеет загружать из памяти отдельные байты (только слова по 2 байта), не умеет выполнять логические операции, в нём нет флага нуля, а всё-таки справляется с типовыми задачами, и не сказать, что как-то очень громоздко.
Tags: ПЛИС, математика, программки, работа, странные девайсы
Subscribe

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 0 comments