nabbla (nabbla1) wrote,
nabbla
nabbla1

Categories:

Создание библиотек - QuatCore style

Настаёт время соединить толпу ранее написанного кода: обнаружение точек, аффинный алгоритм и процедуры для вывода в терминал или на ЖК-экранчик в "удобочитаемом виде".

И что-то мне кажется, пора уже не копипастить всё это в один файл, а попытаться всё-таки написать "библиотеки" с наиболее часто используемыми функциями - и подключать их к файлу.

Пока что мне кажется, что для этого достаточно уже имеющихся возможностей компилятора QuatCore, а именно простейшей директивы %include...


В языках высокого уровня принято было каждую часть разделять на две части - заголовок и имплементацию. В C и C++ это файл .h для заголовка и .c / .cpp для "тела", в Паскале / Delphi файл один, .pas, но в нём есть секция interface и implementation. (как это в более современных языках, особенно тех что в машинный код в принципе не компилируются, типа java или python, я не знаю, вроде как там проще всё)

И на первом этапе каждый файл компилируется отдельно, при этом чтобы понимать, что за функции предстоит вызывать, и что за структуры используются, к нему подключаются заголовки библиотек. Результатом становится объектный файл - это уже ПОЧТИ машинный код, но на месте адресов для вызова функций и для прыжков по абсолютным адресам пока что сидят некие "фиктивные" значения, и дополнительно прилагается некая таблица о том, каким байтам в коде соответствует какая из меток, которые ведут "наружу", и пока что мы понятия не имеем, что это такое. Да и собственные "абсолютные адреса" пока неизвестны.

И только когда все объектные файлы будут готовы, запускается линкер, который из этого собирает готовую программу.

Думаю, что для моих задач всё это ПЕРЕБОР!

Во всём этом процессе есть смысл, когда у нас есть БИНАРНЫЕ библиотеки, т.е поставляемые без исходного кода, когда хочется объединить несколько частей, написанных на разных языках программирования, когда нужно обращаться к операционной системе, когда вся эта хренотень становится чрезвычайно громоздкой, так что компиляция занимает десятки минут, часы, или того больше. До сих пор не понимаю, как можно было до такого докатиться, как в принципе возможно накодить сотни мегабайт бинарников???

Но у нас таких проблем не стоит. Самая долгая часть в работе моего компилятора - это вывести результаты работы на экран, всё пишется на одном языке, исходные коды в наличии, весь код пока умещается в один килобайт, и операционная система отсутствует :)

Поэтому будем проще. К примеру, вот файл print.asm:
	;посылает строку куда-нибудь. Пока модуль ввода-вывода всего один, SIO не нужен (нужный модуль по умолчанию будет активен)
	;X указывает на начало строки текста
	;конец обозначается отрицательным числом или НУЛЁМ (необходимо для работы с байтами)
	;меняет значение регистра Acc (в нём будет лежать значение "одна вторая младшего разряда") 
	;и X (он указывает на последний символ строки, ноль или отр. число)
	
%include "QuatCoreConsts.inc"
;нужна константа RoundZero	
	
.code
	print proc
				;надо поменять местами SP и X
				%CheckHazards OFF
				SP	X
				X	SP
				%CheckHazards ON
	
		@@start:	ZAcc	RoundZero
				SUB	[SP]
				JGE	@@finish	;увы, теперь из процедуры так просто не выпрыгнешь
				OUT	[SP++]
				JMP	@@start
		@@finish:
				%CheckHazards OFF
				SP	X
				X	SP
				%CheckHazards ON
				JMP	[--SP]
	print endp


Красивый был вариант print в 5 строк, но всё-таки нам нужен стек... Хорошо хоть, сообразили, что два регистра можно в две строки местами поменять :) Увы, теперь "выпрыгнуть" из середины цикла прямо из процедуры уже не получится - нужно перевернуть их назад.

Что интересно: даже в эту несложную процедуру нужно включать файл QuatCoreConsts.inc. Он же наверняка будет включаться и в самом начале "основного кода", так что определённые там величины, типа UART, ETH, SD, RoundZero и пр., будут определены повторно, на что мы получим ругань.

Директив наподобие #define и #ifdef у нас пока нет, равно как и #pragma once, но мне чего-то и не хочется их вводить.
Почему бы просто не вести список подключённых файлов, и не подключить один файл дважды? Мне сложно придумать ситуацию, где один и тот же файл реально нужно включить дважды. Нет, можно, конечно, сделать замену вызову функции - в том месте, где она нужна, вставлять целый файл, такой колхозный inline, но по мне так это изврат.

Вот ещё один файл, Bin2Bcd.asm:
;компилятор должен понимать, что означают символы '-' и '0', для этого в осн. программе надо подключить Win1251.inc или другой файл "кодировки".

.rodata
	BCDtable dw 1,10,100,1000,10000

.code
	;в ACC лежит число со знаком, хотим его вывести в десятичной форме по UART0
	;используем регистры i, k, Y, Acc
	;в конце работы k=0
	; SignedBin2Bcd proc
				; SUB		0
				; JGE		BetterBin2Bcd
				; OUT		'-'
				; 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]
				OUT		Acc
				[SP+1]		0
				Acc		[SP]
				kloop		@@start	
				JMP		[--SP]	
	BetterBin2Bcd endp


Тут немножко интереснее: есть как сегмент .code, так и .rodata (Read-Only data). Это нормально, они могут сколько угодно раз перемежаться.

С кодировками я, возможно, перемудрил. Когда-то у меня был ЖК-экранчик с какой-то наркоманской кодировкой, поэтому решил себя обезопасить - и все символы в одинарных кавычках определить в "файле кодировки". В итоге, символы '0' и '-' просто так восприняты не будут. Но файл кодировки непосредственно здесь я не добавляю - он должен быть добавлен в основной файл. У меня сейчас есть Win1251.inc и LCD_code_page_1.inc, которые ВНЕЗАПНО оказались одинаковыми :)

Ну а основной файл в итоге будет выглядеть как-то так:
;простейший Bin2Bcd
%include "Win1251.inc"
%include "QuatCoreConsts.inc"
.rodata
	OurString 	db 'Степени двойки:',13,10,0
	ZeroStr 	db 'Нолик:',13,10,0
	
.code
	main proc
				SP		Stack
				SIO		UART
				X		OurString
				CALL 		print
				j		15
				ACC		1
		@@start:	C		Acc
				CALL		BetterBin2Bcd	;очередное число
				OUT		13
				OUT		10
				Acc		C
				ADD		Acc
				jLOOP		@@start
				X		ZeroStr
				CALL		print
				Acc		0
				CALL		BetterBin2Bcd
				
		@@endless: 	JMP 		@@endless
	main endp		
	
%include "Print.asm"
%include "Bin2Bcd.asm"

.data
	Stack	dw	?,?,?,?


Немножко необычно, но вроде смысл прослеживается. Код и данные добавляются ровно в том порядке, в каком компилятор разбирает этот файл, попутно открывая те файлы, которые в %include. Поэтому функции должны следовать уже после main (выполнение начинается тупо с нулевого адреса!), а стек желательно запихать в самый конец, чтобы он случайно не затёр какие-то полезные данные.

Завтра поиграемся...
Tags: #define, #ifdef, #pragma, ПЛИС, программки, работа, странные девайсы
Subscribe

Recent Posts from This Journal

  • Тестируем atan1 на QuatCore

    Пора уже перебираться на "железо" потихоньку. Решил начать с самого первого алгоритма, поскольку он уже был написан на ассемблере. В программу внёс…

  • Формулы приведения, что б их... (и atan на ТРЁХ умножениях)

    Формулу арктангенса на 4 умножениях ещё немножко оптимизировал с помощью алгоритма Ремеза: Ошибка уменьшилась с 4,9 до 4,65 угловой секунды, и…

  • Алгоритм Ремеза в экселе

    Вот и до него руки дошли, причина станет ясна в следующем посте. Изучать чужие библиотеки было лениво (в том же BOOSTе сам чёрт ногу сломит), писать…

  • atan на ЧЕТЫРЁХ умножениях

    Мишка такой человек — ему обязательно надо, чтоб от всего была польза. Когда у него бывают лишние деньги, он идёт в магазин и покупает какую-нибудь…

  • Ай да Пафнутий Львович!

    Решил ещё немного поковыряться со своим арктангенсом. Хотел применить алгоритм Ремеза, но начал с узлов Чебышёва. И для начала со своего "линейного…

  • atan(y/x) на двух умножениях!

    Чего-то никак меня не отпустит эта тема, всё кажется, что есть очень простой и эффективный метод, надо только его найти! Сейчас вот такое…

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 3 comments