nabbla (nabbla1) wrote,
nabbla
nabbla1

Categories:

Проверяем "библиотеки" и вывод чисел в десятичной форме

Для начала мы ещё чуть доработали компилятор: он должен вести список файлов, которые он прочитал (т.е основной + все, загруженные через %include) и понимать, к какому из них относится текущая обрабатываемая строка, чтобы в сообщении об ошибке сказать, в каком файле эта ошибка.

Для вчерашнего примера TestBCD.asm, которая подключает Win1251.inc и QuatCoreConsts.inc, а также print.asm (в свою очередь подключающий QuatCoreConsts.inc) и Bin2Bcd.asm, мы получили успешную компиляцию - раньше мы получали жалобы на повторное определение метки UART (из QuatCoreConsts.inc) и пр. Сейчас повторно QuatCoreConsts.inc не подключается, что не может не радовать.

Единственно предупреждение, что мы получили, касается Hazard'ов:

Обрабатываем файл TestBin2BcdLib.asm
Конфликт (Hazard) между командами [SP+1] и [SP], файл Bin2Bcd.asm, процедура BetterBin2Bcd, строки:
				[SP+1]	0
				Acc	[SP]
Вставляем NOP


Да, теперь указывается не только процедура, но и файл, что упростит нам жизнь.

Надо попробовать убрать этот Hazard - и прошить всё это в ПЛИС!



Это у нас как раз процедура для вывода числа в десятичной форме. Подробнее о ней писали здесь (28 января 2020 года, ужас какой...)

Нас интересует кусочек ближе к концу:

@@proceed:	[SP]	Acc		;сейчас аккумулятор пригодится...
		Acc	'0'
		ADD	i
		SUB	[SP+1]
		OUT	Acc
		[SP+1]	0
		Acc	[SP]
		kloop	@@start


Здесь мы уже "занулили" очередной разряд, в аккумуляторе лежит число без старших разрядов, а в регистре i: цифра от 0 до 9, которую мы должны вывести.

Поэтому мы сохраняем значение из аккумулятора в стек, запихиваем туда взамен символ '0' (0x30 в ASCII) и прибавляем i, после чего отправляем "наружу" командой OUT.

И затем нужно совершить два действия: вернуть в аккумулятор значение из стека, а также занести нолик в [SP+1]. Эта "локальная переменная" реализует нам логику пропуска ведущих нулей в числе, чтобы выводилось просто 0 или просто 32 вместо 00000 или 00032. Занося в [SP+1] нолик, мы говорим: "уже был выведен разряд, теперь пропускать нули НЕЛЬЗЯ!", иначе вместо 105 вышло бы 15.

Короче, две этих команды,
Acc [SP]
и
[SP+1] 0
конфликтуют, но они НИКАК НЕ СВЯЗАНЫ МЕЖДУ СОБОЙ.

Так что тупо меняем их местами:
	@@proceed:	[SP]	Acc		;сейчас аккумулятор пригодится...
			Acc	'0'
			ADD	i
			SUB	[SP+1]
			OUT	Acc
			Acc	[SP]
			[SP+1]	0				
			kloop	@@start


Дёшево и сердито. Жаль, компилятор пока не научился такие штуки делать самостоятельно, если видит, что порядок выполнения не имеет значения!

В этот раз никаких предупреждений не выдаётся, основная статистика:

Ширина адреса сегмента кода (и регистра PC):           6  
Ширина адреса сегмента данных (и регистров X,Y,Z,SP):  5  
Ширина сумматора для относительных прыжков:            6  
Количество инициализированных слов данных:             36 
Количество инициализированных слов кода:               48 
Количество адресов процедур:                           2  


Листинг кода:
    main proc
00  FD74                  SP      Stack
01  1003                  SIO     UART
02  CD03                  X       OurString
03  F3B4                  CALL    print
04  A17B                  j       15
05  8040                  ACC     1
06  8A80      @@start:    C       Acc
07  F3B8                  CALL    BetterBin2Bcd   ;очередное число
08  0058                  OUT     13
09  0028                  OUT     10
0A  8083                  Acc     C
0B  8280                  ADD     Acc
0C  A931                  jLOOP   @@start
0D  CD01                  X       ZeroStr
0E  F3B4                  CALL    print
0F  8000                  Acc     0
10  F3B8                  CALL    BetterBin2Bcd
11  B045      @@endless:  JMP     @@endless
    main endp       
    print proc
12  FDCD                  SP      X
13  CDFD                  X       SP
14  8874      @@start:    ZAcc    RoundZero
15  83FC                  SUB     [SP]
16  BC4D                  JGE     @@finish    ;увы, теперь из процедуры так просто не выпрыгнешь
17  00F3                  OUT     [SP++]
18  B015                  JMP     @@start
19  FDCD                  SP      X
1A  CDFD                  X       SP
1B  B0FF                  JMP     [--SP]
    print endp
    BetterBin2Bcd proc
1C  A213                  k       4   ;номер обрабатываемого разряда
1D  F07F                  [SP+1]  -1  ;-1 означает, что значащих цифр ещё не было, 0-что появились
1E  DD24                  Y       BCDtable                
1F  A0F0      @@start:    i       [SP+1]
20  83D8      @@sub:      SUB     [Y+k]
21  A474                  i++     0
22  BC03                  JGE     @@sub
23  82D8                  ADD     [Y+k]
24  A873                  iLOOP   @@proceed   ;прыжка не будет, если [SP+1]=-1 и текущий разряд нулевой
25  AA7D                  kloop   @@start
26  F000                  [SP+1]  0
27  FC80      @@proceed:  [SP]    Acc     ;сейчас аккумулятор пригодится...
28  8006                  Acc     '0'
29  82A0                  ADD     i
2A  83F0                  SUB     [SP+1]
2B  0080                  OUT     Acc
2C  80FC                  Acc     [SP]
2D  F000                  [SP+1]  0               
2E  AA7D                  kloop   @@start 
2F  B0FF                  JMP     [--SP]  
    BetterBin2Bcd endp


И листинг памяти:
OurString:      00  0xD1CD
OurString[1]:   01  0xF2EE
OurString[2]:   02  0xE5EB
OurString[3]:   03  0xEFE8
OurString[4]:   04  0xE5EA
OurString[5]:   05  0xED3A
OurString[6]:   06  0xE80D
OurString[7]:   07  0x200A
OurString[8]:   08  0xE400
OurString[9]:   09  0xE2??
OurString[10]:  0A  0xEE??
OurString[11]:  0B  0xE9??
OurString[12]:  0C  0xEA??
OurString[13]:  0D  0xE8??
OurString[14]:  0E  0x3A??
OurString[15]:  0F  0x0D??
OurString[16]:  10  0x0A??
OurString[17]:  11  0x00??
BCDtable:       12  0x0001
BCDtable[1]:    13  0x000A
BCDtable[2]:    14  0x0064
BCDtable[3]:    15  0x03E8
BCDtable[4]:    16  0x2710
Stack:          17  ????
Stack[1]:       18  ????
Stack[2]:       19  ????
Stack[3]:       1A  ????
                1B  ????
                1C  ????
                1D  ????
                1E  ????
                1F  ????


Похоже на правду: первые адреса заняла строка OurString ("Степени двойки:"), затем строка ZeroStr ("Нолик:") поделила с ней первые слова. Некоторое количество младших байт оказалось незанятым, а потом уже за ними пристроилась BCDtable, и под самый конец Stack.

Ещё одна мысль пришла: с нашей весёлой адресацией мы давали интерпретацию старшим битам 00 (работаем со словами), 10 (с байтами, берём младший), 11 (с байтами, берём старший), а вот 01 пока означает то же самое, что и 00. А можно на эту комбинацию поставить какой-нибудь светодиодик на макетной плате, потому как она будет свидетельствовать о переполнении стека :)

Как ни странно, таблица непосредственных значений сейчас вообще синтезировалась в 0 ЛЭ:
//таблица непосредственных значений, сгенерированная под конкретный исполняемый код
module QuatCoreImmTable (input [7:0] SrcAddr, output [15:0] Q);
	wire[6:0] adr = SrcAddr[6:0];
	assign Q[0]=adr[6];
	assign Q[1]=adr[5];
	assign Q[2]=adr[4];
	assign Q[3]=adr[3];
	assign Q[4]=adr[2];
	assign Q[5]=adr[1];
	assign Q[6]=adr[0];
	assign Q[7]=adr[0];
	assign Q[8]=adr[0];
	assign Q[9]=adr[0];
	assign Q[10]=adr[5];
	assign Q[11]=adr[5];
	assign Q[12]=adr[5];
	assign Q[13]=adr[5];
	assign Q[14]=adr[5];
	assign Q[15]=adr[5];
//Непосредственные значения и их адреса:
// Значение (dec) Значение (hex) Маска Адрес Где используется                                        
// 23             0017           007F  0074  SP Stack/ZACC RoundZero/i++ 0                           
// 96             0060           007F  0003  SIO UART/X OurString/JGE BetterBin2Bcd::@sub            
// 15             000F           001F  007B  j 15                                                    
// 1              0001           FFFF  0040  Acc 1                                                   
// 13             000D           03FF  0058  OUT 13                                                  
// 10             000A           03FF  0028  OUT 10                                                  
// 6              0006           003F  0031  jLOOP main::@start                                      
// 64             0040           007F  0001  X ZeroStr                                               
// 0              0000           FFFF  0000  Acc 0/[SP+1] 0/[SP+1] 0                                 
// 17             0011           003F  0045  JMP main::@endless                                      
// 25             0019           003F  004D  JGE print::@finish                                      
// 20             0014           003F  0015  JMP print::@start                                       
// 4              0004           001F  0013  k 4                                                     
// 65535          FFFF           FFFF  007F  [SP+1] -1                                               
// 18             0012           007F  0024  Y BCDtable                                              
// 39             0027           003F  0073  iLOOP BetterBin2Bcd::@proceed                           
// 31             001F           003F  007D  kLOOP BetterBin2Bcd::@start/kLOOP BetterBin2Bcd::@start 
// 48             0030           FFFF  0006  Acc '0'                                                 
endmodule


А уж QuatCoreCallTable тем более.

Но чтобы эта программка правильно заработала, нам нужно всё-таки побороть жадность и расширить как SP, так и X на 2 бита, и для кучи выдавать эти дополнительные биты на шину данных, иначе они не смогут обменяться значениями!

Ничего особенно интересного, в 4 модулях заменяем RamWidth-1 на RamWidth+1 - и золотой ключик у нас в кармане. Растолстели наверное на пару ЛЭ, не более того.

Вся конструкция в целом синтезируется в 1319 ЛЭ, пока жить можно. Напоминаем, это с видеопроцессором, генератором тестового изображения и селектором синхроимпульсов, хоть всё это "новое железо" пока лежит мёртвым грузом.

Наконец, прошиваем по JTAG и получаем результат:



С первого раза :)

Дальше на очереди - прошить программу обнаружения точек с выводом результатов работы по UART. Вот это и называется "Стремительным домкратом".

UPD. Ещё сделали файлик SetClock.asm с кодом для настройки тактовой частоты в 25 МГц. Подключили его в самом начале процедуры main. Всё в порядке, выдаёт то же самое, но на скорости 921 600.
Tags: ПЛИС, программки, работа, странные девайсы
Subscribe

Recent Posts from This Journal

  • Огарь крупным планом

    Прям как на пьедестале, гордый такой, здоровенный, песенку спел, потом спустился водички попить, небось горло пересохло. Только на видео я заметил,…

  • Я создал монстра!

    Вот нормальная счастливая пара разъёмов ОНЦ-БС-1-10/14-Р12-2-В и ОНЦ-БС-1-10/14-В1-2-В: У розетки кроме основного выступа, отмечающего "верх",…

  • Нахождение двух самых отдалённых точек

    Пока компьютер долго и упорно мучал симуляцию, я пытался написать на ассемблере алгоритм захвата на ближней дистанции. А сейчас на этом коде можно…

  • Слишком общительный счётчик

    Вчера я чуть поторопился отсинтезировать проект,параметры не поменял: RomWidth = 8 вместо 7, RamWidth = 9 вместо 8, и ещё EnableByteAccess=1, чтобы…

  • Балансируем конвейер QuatCore

    В пятницу у нас всё замечательно сработало на симуляции, первые 16 миллисекунд полёт нормальный. А вот прошить весь проект на ПЛИС и попробовать "в…

  • Огари разговаривают

    Сегодня по пути на работу встретил огарей прямо в Лосином острове, на берегу Яузы. Эти были на удивление бесстрашны, занимались своими делами, не…

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 0 comments