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

  • Ремонт лыжных мостиков

    Вернулся с сегодняшнего субботника. Очень продуктивно: отремонтировали все ТРИ мостика! Правда, для этого надо было разделиться, благо народу…

  • Гетто-байк

    В субботу во время Великой Октябрьской резни бензопилой умудрился петуха сломать в велосипеде. По счастью, уже на следующий день удалось купить…

  • А всё-таки есть польза от ковариаций

    Вчера опробовал "сценарий", когда варьируем дальность от 1 метра до 11 метров. Получилось, что грамотное усреднение - это взять с огромными весами…

  • Так есть ли толк в ковариационной матрице?

    Задался этим вопросом применительно к своему прибору чуть более 2 недель назад. Рыл носом землю с попеременным успехом ( раз, два, три, четыре),…

  • Big Data, чтоб их ... (4)

    Наконец-то стряхнул пыль с компьютерной модели сближения, добавил в неё код, чтобы мы могли определить интересующие нас точки, и выписать…

  • Потёмкинская деревня - 2

    В ноябре 2020 года нужно было сделать скриншот несуществующей программы рабочего места под несуществующий прибор, чтобы добавить его в документацию.…

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 3 comments