Геометрия экрана "Специалист"

Обсуждение советского компьютера Фахiвець / Специалист и его развитие

Moderator: Lavr

User avatar
Lavr
Supreme God
Posts: 16676
Joined: 21 Oct 2009 08:08
Location: Россия

Post by Lavr »

HardWareMan wrote:а уже потом натянуто на сетку частот видеосигнала (получилось 2МГц на процессоре заместо 1,7МГц в РКшке).
А в "Орионе" - 2.5МГц и тоже натянуто на ту же сетку частот и тот же арбитр... :wink:
Как же так по-разному получилось? При фактически идентичной схемотехнике?
iLavr
User avatar
Lavr
Supreme God
Posts: 16676
Joined: 21 Oct 2009 08:08
Location: Россия

Post by Lavr »

HardWareMan wrote:есть следующее мнение: 8МГц Специалиста выбраны именно из-за достижения простоты синхрогенератора, т.к. частота кратна частоте строк в степени двойки. А вот 10МГц Ориона уже появились, по моему мнению, для исправления аспекта, чтобы получить полноценные 4:3. Ну и бордюр в те времена был полезен ибо не каждый мог подстроить размер растра телевизора.
Вот я подчеркнутую мысль и высказал, собственно говоря:
Lavr wrote:за основу взята схема прозрачной регенерации ДОЗУ, частоты которой были выбраны
так, чтобы хорошо попадать в строчную и кадровую развертки.
Если посмотреть расчет - то в параметры стандарта там всё очень четко уложено,
чего не скажешь об "Орионе".

И про какие "исправления аспекта" можно говорить, когда у "Ориона" экран заужен
при тех же изначальных 384х256?

Ну и вопрос я свой адресовал-таки нашему авторитетному источнику - PNP - чтобы
услышать, как оно было на сАмом деле...
А то мы много тут чего предполагали, а он нас покритиковал чутка...

Так что - просто хотелось бы узнать правду от человека, близкого к первоисточнику.
iLavr
User avatar
Lavr
Supreme God
Posts: 16676
Joined: 21 Oct 2009 08:08
Location: Россия

Post by Lavr »

HardWareMan wrote:У меня на телевизоре, настроенном на обычный видеосигнал, у Специалиста круг был немного растянут по горизонтали, в то время как у Ориона нет.
А у меня на зелёном венгерском мониторе "Орион" круг был просто идеальным!
Огорчу тебя также тем, что круг выходил совершенно правильным кругом на печать
моим любимым принтером тех времен - УВВПЧ.
То есть имел место полный "ВизВиг"...

Так что это у тебя с телевизором что-то не тоё было...
iLavr
petrenko
Doomed
Posts: 598
Joined: 10 Mar 2012 16:21
Location: РФ

Post by petrenko »

HardWareMan wrote:Это я тебя огорчу. 384х256 в самом деле соотношение 4:3.
В результате огорчился не он, а я, поскольку не могу никак подобрать систему, в которой 384 поделённое на 256 будет равно 4/3 ... :cry:

В известных мне системах почему то 384/256==3/2 .. Странно.
Может в разных школах разные математики ? :roll:

А правду говорят, что в СССР была СЕКАМ и из 625 строк полного кадра видимыми должны были быть 525 ? А в полукадре соответственно 262.5 строк видимых ?
А то может и справочники разные..
Вот который я читал, в том про черезстрочную кадровую развёртку 50Гц~~20мс-полукадр, 25Гц~~40мс-полный кадр и строчную частоту 15625Гц что то написано, а в каком другом справочнике может всё и по другому.. :-?
petrenko
Doomed
Posts: 598
Joined: 10 Mar 2012 16:21
Location: РФ

Post by petrenko »

HardWareMan wrote:Хаха, точно. Я никогда не делил эти цифры...
Ну вот я опять огорчился. :cry:
У нас в начальной ( и средней ) школе вообще никогда не делили цифры. Делили только числа.( ибо "цифра есть значок, употребляемый для записи чисел", а "число есть абстрактная форма записи некоего реального количества". - согласно определению из учебника.. )
HardWareMan wrote:... Если 256 умножить на 1.3, то получаем ~332 точки ...
А вот если умножить не на 1.3, а на дробь (4/3) то получится 256*(4/3)==341.(3) ( для организации счётчиков в графическом контроллере лучше округлить в большую сторону, т.е.342 пиксела ), соответственно 262.5*(4/3)==350
Таким образом, полагая пиксел квадратным, для соотношения 4 к 3 получаем "правильный" экран 342 на 256 пиксел с бордюром слева и справа по (350-342)/2==4 пиксела, а снизу и сверху по (262.5-256)/2==3.25 пиксела ( тоже придётся округлять )
HardWareMan wrote:А вот про строки тоже не ясно, сколько именно строк должно быть в КОХ.
Со строками всё вполне даже ясно.
В полном кадре 625 всего, из них 525 видимых, 100 не отображаются
, соответственно в полукадре 312.5 всего, из них 262.5 видимых, 50 не отображаются - идёт обратный ход кадровой развёртки.
По времени тоже всё ясно : 20мс/312.5==64мкс==0.064мс
0.064мс*262.5==16.8мс идёт отображение
0.064мс*50==3.2мс идёт обратный ход кадровой развёртки
petrenko
Doomed
Posts: 598
Joined: 10 Mar 2012 16:21
Location: РФ

Post by petrenko »

Совершенно верно, именно полагая экран плоским и "правильным".:idea:
Чисто математически идеализируя, то есть.
В реале, понятное дело, надо будет ещё много чего учитывать.
Shaos wrote:А буквы делить вас в школе не учили? ;)
Типа a/b=c ;)
Не знаю, как там в ВУЗ ( у меня неполное среднее, если что.. ), но в школе учили делить некие неизвестные величины, абстрактно изображаемые буквами.
Но сами буквы можно делить разве что на чёрточки и точечки, из которых они и составляются.
Вот как то так..
Вы уж извините, ежели я не в курсе последних достижений британских "учоных"
Last edited by petrenko on 03 Oct 2013 00:11, edited 1 time in total.
petrenko
Doomed
Posts: 598
Joined: 10 Mar 2012 16:21
Location: РФ

Post by petrenko »

"Вау" тута усе такие грамотные, просто жуть..
Куда уж там нам с неполным средним образованием, да постигать сложнейшие тайны..

Зато я теперь знаю, с чего начинаются форумные"мега-холивары"- они начинаются с зашкаливающей грамотности всех участвующих в оных оппонентов.

Всем удачи в освоении компьютера "Фах³вець-85" ! :rotate:

( если кому нужны консультации по арифметике в рамках начальной школы - пожалуйста - можете обращаться, мало ли кто после двух - трёх В.У.З. забыл что-нибудь, ну или без калькулятора перемножить или разделить не сможет - поможем, чем можем, мы люди простые, добрые.. )
petrenko
Doomed
Posts: 598
Joined: 10 Mar 2012 16:21
Location: РФ

Post by petrenko »

Не волнуйтесь, я очень добрый, на коллег не обижаюсь.
Просто у меня своеобразное чувство юмора.. :rotate:
А вот без этого самого юмора и вправду можно было бы свихнуться от любой мелочи, хоть даже и от отсутствия "умляута" над "ё" :o
А то, что простые люди иногда что-нибудь могут перепутать - так не всем же повезло с учителями. Вот в одной стране главный ( ГБ-шник кстати ) и тот называет"цифру инфляции" :D , и ничего - терпим..

По теме : несколько не соответствующие соотношению 4 к 3 графические контроллеры многих ЛК - это компромисс, упрощающий организацию счётчиков. "Правильные" контроллеры графического дисплея я видел, но они во-первых сами сложнее, а во-вторых требуют более мало-доступного устройства отображения, нежели бытовой телевизор.
User avatar
Lavr
Supreme God
Posts: 16676
Joined: 21 Oct 2009 08:08
Location: Россия

Post by Lavr »

HardWareMan wrote:На принтер 6337 у меня тоже круг выходил круглый. Но на телевизоре он был овалом. И настраивать круг на нем меня ломало, ибо таблицу УЭИТ он показывал идеально. Так что мимо кассы ты тут с венгерскими накрученными мониторами. :3
А мне кажется это ты всегда мимо кассы... но что бы не спорить, я соглашусь - пусть
у HardWareMan всё самое лучшее, ну а у меня - такое, какое уж было:
Lavr wrote:у меня на зелёном венгерском мониторе "Орион" круг был просто идеальным!
... круг выходил совершенно правильным кругом на печать
моим любимым принтером тех времен - УВВПЧ.
То есть имел место полный "ВизВиг"...
Вероятно потому как одним было влом подстраивать, а другие просто работали за
хорошим монитором.
iLavr
User avatar
Lavr
Supreme God
Posts: 16676
Joined: 21 Oct 2009 08:08
Location: Россия

Алгоритмы Брезенхема

Post by Lavr »

Поскольку у меня заработал он-лайн эмулятор 6502, я занялся программированием на ассемблере
этого процессора. Ну и поскольку, кроме графического экранчика 32х32 точки на 16 цветов в этой
системе устройств практически нет, пришлось вспомнить примитивы растровой графики...

Линии круги и более сложные кривые на растровом устройстве помогают отрисовать Алгоритмы Брезенхема.

Ну и линию отрисовывает Bresenham's line algorithm, суть которого в двух словах заключается в том,
что, поскольку в растровой графике линия аппроксимируется ломаной линией по пикселям, то закрашивается
тот пиксель растра,среднеквадратичное отклонение которого от линии наименьшее.

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

Image

Этот алгоритм я ещё давно реализовывал с помощью одной хорошей книжки по графике, и на языке Васик этот
алгоритм выглядит примерно следующим образом:

Code: Select all

     DEFINT A-Z

     SCREEN 7 ' 320 x 200 graphics; 40 x 25 text format, character box size 8 x 8
              ' Assignment of 16 colors to any of 16 attributes
Start:
COL = 4

' Absolute pixel coordinates for line origin.
x1 = 200
y1 = 140

' Absolute pixel coordinates for line end.
x2 = 250
y2 = 14

  LINE (x1, y1)-(x2, y2), 2 '--- LINE QBASIC для сравнения

DO
  Key$ = INKEY$
LOOP WHILE Key$ = ""

    dy = y2 - y1
    dx = x2 - x1

    IF dy < 0 THEN  '--- (y1 > y2)
       dy = -dy
       stepy = -1
     ELSE
       stepy = 1
    END IF

    IF dx < 0 THEN  '--- (x1 > y2)
       dx = -dx
       stepx = -1
     ELSE
       stepx = 1
    END IF

    dx = dx + dx
    dy = dy + dy

'--Displays a pixel at given absolute (x, y) location
   PSET (x1, y1), COL

    IF dx > dy THEN
       fraction = dy - (dx \ 2)'  Integer division 
       WHILE x1 <> x2
          IF fraction >= 0 THEN
               y1 = y1 + stepy
               fraction = fraction - dx
          END IF
               x1 = x1 + stepx
               fraction = fraction + dy
             PSET (x1, y1), COL
        WEND
     ELSE  ' dx = dy
       fraction = dx - (dy \ 2)'  Integer division 
       WHILE y1 <> y2
          IF fraction >= 0 THEN
             x1 = x1 + stepx
             fraction = fraction - dy
          END IF
             y1 = y1 + stepy
             fraction = fraction + dx
             PSET (x1, y1), COL
        WEND
    END IF
На языке С алгоритм можно воплотить примерно вот так:

Code: Select all

//---------------------------------------------------------------------------
void B_Line (int x1, int y1, int x2, int y2)
{
 if (x1 < x2)
    {
      xi = 1; // Step X ;
      dx = x2 - x1;
    }
     else
    {
      xi = -1; // Step X ;
      dx = x1 - x2;
    }

 if (y1 < y2)
    {
     yi = 1; // Step Y ;
     dy = y2 - y1;
    }
     else
    {
     yi = -1; // Step Y ;
     dy = y1 - y2;
    }

    PutPixel (x1, y1);

 if (dx > dy)
    {
     ai = (dy - dx) * 2;
     bi = dy * 2;
      d = bi - dx;

     while (x1 != x2)
       {
         if (d > 0) 
            {
            y1 += yi; // Step Y ;
             d += ai;
            }
            else    
             d += bi;
            x1 += xi;
         PutPixel (x1, y1);
       }
   }
 else
   {
     ai = (dx - dy) * 2;
     bi = dx * 2;
      d = bi - dy;

     while (y1 != y2)
       {
         if (d > 0) 
            {
             x1 += xi;
              d += ai;
            }
           else 
              d += bi;
             y1 += yi;
         PutPixel (x1, y1);
       }
   }
Ну а на ассемблере 6502 этот алгоритм реализуется следующим образом:

Code: Select all

;----------------------------------
;--- Random Lines with ------------
;--- Bresenham's line algorithm ---
;   Click [Compile] and [  Run  ]
;----------------------------------
  *= $0010
l_dx:
  *= $0011
l_dy:
  *= $0012
l_xi:
  *= $0013
l_yi:
  *= $0014
l_ai:
  *= $0015
l_bi:
  *= $0016
l_d:
  *= $0017
l_x1:
  *= $0018
l_y1:
  *= $0019
l_x2:
  *= $001a
l_y2:
  *= $001b
l_XY:
  *= $001c
h_XY:
  *= $001d
rCOL:

  *= $0600
start:
  LDA #16;    Center
  STA l_x1;   X1 = 16
  STA l_y1;   Y1 = 16
loop:
  LDA $fe;    A = RND
  AND #$1F;   A <= 32
  STA l_x2;   X2 = RND <= 32
  LDA $fe;    A = RND
  AND #$1F;   A <= 32
  STA l_y2;   Y2 = RND <= 32
  LDA $fe;    A = RND
  STA rCOL;   COLOR = RND
  JSR line;   LINE(X1,Y1-X2,Y2)
  LDA l_x2;
  STA l_x1;   X1 = X2
  LDA l_y2;
  STA l_y1;   Y1 = Y2
  JMP loop

  *= $c100
line:
x1mx2:  LDA l_x1
  CMP l_x2;       x1 - x2
  BCC x1mx2_; if (x1 < x2)
  JMP x1wx2;else [x1 => x2]
x1mx2_:
;--------------  then [x1 < x2]
  LDA #1
  STA l_xi;   xi = 1;
  LDA l_x2
  SEC;    BORROW = 0
  SBC l_x1;   x2 - x1 - BORROW
  STA l_dx;   dx = x2 - x1
  JMP y1my2
;--------------  else [x1 => x2]
x1wx2: lda #255;     A = -1
  STA l_xi;    xi = -1; -> step_X
  LDA l_x1
  SEC;     BORROW = 0
  SBC l_x2;    x1 - x2 - BORROW
  STA l_dx;    dx = x1 - x2
;- deciding what direction to draw + steps
y1my2: ;   [y1 < y2]
;-- if
  LDA l_y1
  CMP l_y2;  if (y1 < y2)
  BCC y1my2_
  JMP y1wy2
y1my2_:
;-- then
  LDA #1;       A = 1;
  STA l_yi;    yi = 1; -> step_Y
  LDA l_y2
  SEC;     BORROW = 0
  SBC l_y1;    y2 - y1 - BORROW
  STA l_dy;    dy = y2 - y1
  JMP skok1
;-- else [y1 > y2]
y1wy2:
  LDA #255;      A = -1;
  STA l_yi;     yi = -1; -> step_Y
  LDA l_y1
  SEC
  SBC l_y2
  STA l_dy;     dy = y1 - x2
skok1:
;-- put first pixel
  JSR Pset; putpix(x1,y1);
;-- check 'primary axis' (longer distance)
  LDA l_dx
  CMP l_dy; if (dx>dy)  // (dy<dx)
  BCC wiod_oy
wiod_ox:
;-- solve ai
  LDA l_dy
  SEC
  SBC l_dx
  CLC
  ROL;        a
  STA l_ai;   ai = (dy-dx)*2
;-- solve bi
  LDA l_dy
  CLC
  ROL;        a
  STA l_bi;   bi = dy * 2
;-- solve d
  LDA l_bi
  SEC
  SBC l_dx
  STA l_d ;    d = bi - dx
;-- while (x1 != x2)
whx1rx2:
  LDA l_x1
  CMP l_x2
  BNE if_d
  JMP l_fin
if_d:
;-- if (d > 0)
  LDA l_d
  CMP #0
  BEQ _a
  BPL _else
;-- < 0
_a:
  LDA l_d
  CLC
  ADC l_bi
  STA l_d;     d += bi;
  JMP _reszta

;-- else [d>0]
_else:
  LDA l_y1
  CLC
  ADC l_yi
  STA l_y1;    y1 += yi;
  LDA l_d
  CLC
  ADC l_ai
  STA l_d;     d += ai;
;-- end else
_reszta:
  LDA l_x1
  CLC
  ADC l_xi
  STA l_x1;     x1 += xi;
;-- putpix(x1,y1);
  JSR Pset
  JMP whx1rx2; (petla while: )

wiod_oy:
;-- solve ai
  LDA l_dx
  SEC
  SBC l_dy
  CLC
  ROL;         a
  STA l_ai;    ai = (dx-dy)*2
;-- solve bi
  LDA l_dx
  CLC
  ROL ;a
  STA l_bi;    bi = dx * 2
;-- solve d
  LDA l_bi
  SEC
  SBC l_dy
  STA l_d;     d = bi - dy
why1ry2:
;----- while (y1 != y2)
  LDA l_y1
  CMP l_y2
  BNE if_nd
  JMP l_fin

if_nd:
;-- if (d > 0) then
  LDA l_d
  CMP #0
  BEQ _b
  BPL _elsey
_b:  ; <0
  LDA l_d
  CLC
  ADC l_bi
  STA l_d;      d += bi;
  JMP _resztay
;-- else [d > 0]
_elsey: ; >0
  LDA l_x1
  CLC
  ADC l_xi
  STA l_x1;     x1 += xi;
  LDA l_d
  CLC
  ADC l_ai
  STA l_d;       d += ai;
;-- end else
_resztay:
  LDA l_y1
  CLC
  ADC l_yi
  STA l_y1;      y1 += yi;

;-- putpix(x1,y1);
  JSR Pset
  JMP why1ry2
;-- The END --
l_fin:
  RTS

Pset:
  LDA l_y1
  ASL;      2* l_x1
  TAX;  X = 2* l_x1
  LDA offs,x
  INX
  CLC
  ADC l_x1
  STA l_XY
  LDA offs,x
  ADC #$02
  STA h_XY
  LDX #0
  LDA rCOL
  STA ($1B,X)
  RTS
offs:
  dcb $00,$00
  dcb $20,$00
  dcb $40,$00
  dcb $60,$00
  dcb $80,$00
  dcb $a0,$00
  dcb $c0,$00
  dcb $e0,$00
  dcb $00,$01
  dcb $20,$01
  dcb $40,$01
  dcb $60,$01
  dcb $80,$01
  dcb $a0,$01
  dcb $c0,$01
  dcb $e0,$01
  dcb $00,$02
  dcb $20,$02
  dcb $40,$02
  dcb $60,$02
  dcb $80,$02
  dcb $a0,$02
  dcb $c0,$02
  dcb $e0,$02
  dcb $00,$03
  dcb $20,$03
  dcb $40,$03
  dcb $60,$03
  dcb $80,$03
  dcb $a0,$03
  dcb $c0,$03
  dcb $e0,$03
;------end-------------------------
А результат работы этой программы - следующий:

------------Image

Самое интересное, как реализовать этот самый: PSET (x1, y1) или PutPixel (x1, y1) ...

На ассемблере 6502 я это сделал табличным методом и немного неоптимально сточки зрения
режимов адресации 6502.
Но суть вот какая: поскольку точке экрана соответствует 1 байт памяти, а размер экрана -
32х32 точки, и начало экранной области - в $0200, то от координат экрана, к адресам памяти
переходим по простой формуле ADDRxy = $0200 + Y *$20 + X.
Собственно, Y *$20 и вычисляется таблично для скорости.

А вот в графике "Специалиста" этот процесс чуть сложнее, поскольку на экране отображаются
отдельные биты каждого байта экранной области, и как с ними работают - я расскажу далее, раз
уж я завел речь о растровой графике в ветке ПК "Специалист"...
iLavr
User avatar
Lavr
Supreme God
Posts: 16676
Joined: 21 Oct 2009 08:08
Location: Россия

Организация экранного ОЗУ

Post by Lavr »

Экранное ОЗУ ПК "Специалист" начинается с ячейки 9000Н (—28672) и заканчивается ячейкой
0BFFFH (—16385).
Каждому биту в случае монохромного экрана соответствует точка (1 — светлая, 0 — темная).

Image

Всего в строке выводится на экран 48 байт. Для того чтобы получить 64 символа в строке,
подпрограмма вывода символа на экран в матрице 5х7 (C037Н) уплотняет их по горизонтали.
В одном байтовом столбце - 256 байт по оси Y. А один байт - 8 графических точек по оси Х.

Таким образом, сдвигу на 8 бит по оси Х соответствует сдвиг на 256 байт от начала экрана - 9000H.
Содержимое экранного ОЗУ выводится на дисплей таким образом, что координата байта по оси Х
соответствует старшему байту адреса в машинном представлении, а координата Y — младшему байту.

Исходя из этих соотношений алгоритм вывода точки на экран следующий: по координате Х находим
адрес столбца экрана, прибавляем координату Y и находим нужный байт. В этом байте устанавливаем
(гасим) бит, номер которого слева указан в 3-х младших битах экранной координаты Х.

На ассемблере это выглядит следующим образом:

Code: Select all

;--- PLOT X, Y, Z
PLOT:
  PUSH H;         Save HL
  LHLD X_c;       X-coord;
  PUSH H;         HL = X-coord;
  LXI  D,0FE80H ; DE = -384
  DAD  D;         HL = X - 384
  JC   ERR; ----- error: X > 384;
  POP  H;         HL = X-coord;
  MOV  A,L
  ANI  07H; 0000.0111b 8-lsb bits
  DAD  H; HL * 2
  DAD  H; HL * 4
  DAD  H; HL * 8
  DAD  H; HL * 16
  DAD  H; HL * 32
  LXI  D,9000H; Screen 1-st byte
  DAD  D; 9000H + HL * 32
  MOV  C,A
  LDA  Y_c;       Y-coord;
  MOV  L,A; HL - Byte at X,Y - coord;

  MVI  A,01H
SBT:RRC;    Set bit in Byte at X,Y - coord;
  DCR  C
  JP   SBT

  CALL PUT
  POP  H;         Restore HL;
  RET

PUT:MOV  C,A
  LDA  Z_p
  CPI  01H
  JZ   K01
  CPI  02H
  JZ   K02
  CPI  03H
  JZ   K03
  RET

K01:MOV  A,C; AND Screen BIT;
  CMA
  ANA  M
  MOV  M,A
  RET

K02:MOV  A,C; OR Screen BIT;
  ORA  M
  MOV  M,A
  RET

K03:MOV  A,C; XOR Screen BIT;
  XRA  M
  MOV  M,A
  RET

ERR:    ; error: X > 384;
  POP  H;         Restore HL;
  POP  H;         Restore HL;
  RET

X_c:DB   00H
  DB   00H
Y_c:DB   00H
Z_p:DB   02H

  END
iLavr
User avatar
Lavr
Supreme God
Posts: 16676
Joined: 21 Oct 2009 08:08
Location: Россия

Post by Lavr »

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

Image

При этом, естественно, отталкиваются от уравнения окружности: R^2 = X^2 + Y^2

Более подробно все выкладки можно посмотреть, к примеру, вот здесь...

А на языке Васик этот алгоритм выглядит даже довольно просто:

Code: Select all

'--- "A Fast Bresenham Type Algorithm For Drawing Ellipses" by John Kennedy ---

     DEFINT A-Z

     SCREEN 12
px = 160
py = 120
 r = 100

 f = 1 - r
dx = 1
dy = -2 * r

 x = 0
 y = r

PSET (px, py - r)
PSET (px, py + r)
PSET (px - r, py)
PSET (px + r, py)

WHILE (x < y)

  IF (f >= 0) THEN
     y = y - 1
    dy = dy + 2
     f = f + dy
  END IF

   x = x + 1
  dx = dx + 2
   f = f + dx

  PSET (px + x, py + y)
  PSET (px + x, py - y)
  PSET (px - x, py - y)
  PSET (px - x, py + y)
  PSET (px - y, py + x)
  PSET (px - y, py - x)
  PSET (px + y, py - x)
  PSET (px + y, py + x)

WEND
Ну а теперь, как это реализовано на языке ассемблера внутри Васика нашего "Специалиста".
(Была у него такая добавочка CIRCLE, разобраться с которой у меня в свое время руки так и не дошли...)

Code: Select all

;-----------------;
; CIRCLE  SP-580  ;
;-----------------;
  ORG  0000H

  JMP  START
RAD:DW   127;--- RADIUS
XPZ:DW   128;--- X-COORD.
Y_c:DB   128;--- Y-COORD.
X_c:DW   0000H
Z_p:DB   02H;--- OR with Screen Byte

START:
  MVI  A,1FH
  CALL 0F80FH
  CALL 0F80FH; Clear Screen
  LHLD RAD;  0=>R=>127
  DAD  H;    HL * 2
  DAD  H;    HL * 4
  DAD  H;    HL * 8
  DAD  H;    HL * 16
  DAD  H;    HL * 32
  DAD  H;    HL * 64
  DAD  H;    HL * 128
  DAD  H;    HL * 256
  DAD  H;    HL * 512
  XCHG;      HL<->DE
  LHLD XPZ;  0=>X=>511
  DAD  D;    HL = 512*R+X
  CALL CIR;
MT0:CALL 0C803H; KBD
  CPI  1BH;  ESC?
  JNZ  MT0;  NOT ESC...
  JMP  0F800H;  EXIT SYSTEM
  NOP
  NOP

K01:MOV  A,C; AND Screen BIT;
  CMA
  ANA  M
  MOV  M,A
  RET

K02:MOV  A,C; OR Screen BIT;
  ORA  M
  MOV  M,A
  RET

K03:MOV  A,C; XOR Screen BIT;
  XRA  M
  MOV  M,A
  RET

ERR:
  POP  H;         Restore HL;
  POP  H;         Restore HL;
  RET

M04:DB   00H;---- xx44h
  DB   00H
M05:DB   00H
  DB   00H
M06:DB   00H
  DB   00H
M07:DB   00H
  DB   00H
M08:DB   00H
  DB   00H
M09:DB   00H
  DB   00H
MASK:
  DB   00H;---- 1_1_1_1 1_1_1_1b

;-- PLOT X,Y,Z
PLOT:
  PUSH H;         Save HL
  LHLD X_c;       X-coord;
  PUSH H;         HL = X-coord;
  LXI  D,0FE80H ; DE = -384
  DAD  D;         HL = X - 384
  JC   ERR; ----- error: X > 384;
  POP  H;         HL = X-coord;
  MOV  A,L
  ANI  07H; 0000.0111b 8-lsb bits
  DAD  H; HL * 2
  DAD  H; HL * 4
  DAD  H; HL * 8
  DAD  H; HL * 16
  DAD  H; HL * 32
  LXI  D,9000H; Screen 1-st byte
  DAD  D; 9000H + HL * 32
  MOV  C,A
  LDA  Y_c;       Y-coord;
  MOV  L,A; HL - Byte at X,Y - coord;

  MVI  A,01H
SBT:RRC;    Set bit in Byte at X,Y - coord;
  DCR  C
  JP   SBT

  CALL PUT
  POP  H;         Restore HL;
  RET

PUT:MOV  C,A
  LDA  Z_p
  CPI  01H
  JZ   K01
  CPI  02H
  JZ   K02
  CPI  03H
  JZ   K03
  RET

; PLOT 512* R + X, Y, Z:' (0=>R=>63)
; PLOT -65536 + 512 * R + X, Y, Z:' (64=>R=>127)
; 0=>R=>127: 512 * 127 = 0FE00h
; 0=>X=>511: 511d = 1FFh - 1 byte + 1 hi bit.
; 0=>Y=>255
;
CIR:
  NOP;         HL = 512*R+X-coord;
  XRA  A;       A = 0; c = 0
  MOV  B,A;     B = 0;

  MOV  A,H;
  RAR;        c765.4321->0 - msb X
  MOV  C,A;   C = H/2 = R;

  MOV  A,B;     B = 0;
  RAL;        6543.210c<-7
  MOV  H,A;   xxx_.L - 0=>X=>511
  SHLD M04;

  MOV  H,B;   H = B = 0;
  MOV  L,C;   L = R; 0=>R=>127;
  SHLD M06;

  LDA  Y_c;   Y-coord: 0=>Y=>255;
  MOV  L,A;   H = B = 0; L = Y ;
  SHLD M05

  MOV  L,B;   L = B = 00h;
  SHLD M08;    = 0000h;
  SHLD M09;    = 0000h;
  DCR  H
  MOV  A,B
  SUB  C
  MOV  L,A
  SHLD M07

  DAD  H
  MVI  C,03H
  DAD  B

  PUSH H
M0B:LDA  MASK
  LXI  H,TB1;---
  CALL M0E
  POP  H

  PUSH H
  DAD  H
  LHLD M08
  JC   M0C
  XCHG
  LXI  H,M06
  DCR  M
  LHLD M07
  INX  H
  SHLD M07
  DAD  D
M0C:DAD  H
  DAD  H
  LXI  D,0006H;
  DAD  D
  POP  D

  DAD  D

  PUSH H
  LHLD M09
  DCX  H
  SHLD M09
  LXI  H,M08
  INR  M
  LDA  M06
  CMP  M
  JC   M0D

  PUSH PSW
  MOV  A,B
  LXI  H,TB2;---
  CALL M0E
  POP  PSW

  JNZ  M0B
M0D:POP  H
  NOP
  RET

M0E:RLC
  MOV  B,A
  MVI  C,04H
M0F:MOV  A,M
  STA  M10+1; mod. Addr.low;
  INX  H
  MOV  A,M
  STA  M11+1; mod. Addr.low;
  MOV  A,B
  RRC
  RRC
  MOV  B,A
  JC   M13
  PUSH H
;--------v low;
M10:LHLD M09
  XCHG
  LHLD M04
  DAD  D
  SHLD X_c
  LXI  D,0FE80H; -384;
  DAD  D
  JC   M12
;--------v low;
M11:LHLD M06
  XCHG
  LHLD M05
  DAD  D
  MOV  A,L
  STA  Y_c
  LXI  D,0FF00H; -256;
  DAD  D
  PUSH B
  CNC  PLOT; EQU  17D8H;
  POP  B
M12:POP  H
M13:DCR  C
  JNZ  M0F
  RET

  NOP
  NOP

TB1:DB   48H;
  DB   4EH;
  DB   4AH;
  DB   4CH;
TB2:DB   48H;
  DB   4CH;
  DB   4AH;
  DB   4EH;
  DB   48H;

  END
Сразу предупреждаю, что программа самомодифицирующаяся, и с другого адреса её запустить трудно,
поскольку в теле есть таблица, привязанная к конкретным смещениям.
Я смещения пересчитывать заленился и выровнял NOP-ами таблицу на подходящие адреса.

В результате получается вот что:

Image

Как я и говорил тут ранее:
Lavr wrote:А у меня на зелёном венгерском мониторе "Орион" круг был просто идеальным!
...круг выходил совершенно правильным кругом на печать моим любимым принтером
тех времен - УВВПЧ. То есть имел место полный "ВизВиг"...
А на ассемблере 6502 код для рисования окружностей у меня вышел следующим:

Code: Select all

;*******************************************
; Draw circles using Bresenham's algorithm *
;*******************************************

;--- ZP base address of data area
    *= $0020; Center Point X;
l_XC:
    *= $0021
h_XC:
    *= $0022; Center Point Y;
l_YC:
    *= $0023
h_YC:
    *= $0024; radius (1 byte)
lRAD:
    *= $0025
hRAD:
    *= $0026; plot point
l_XP:
    *= $0027;
h_XP:
    *= $0028;
l_YP:
    *= $0029;
h_YP:
    *= $002a;  x,y intermediate
l_X1:
    *= $002b;
h_X1:
    *= $002c;
l_Y1:
    *= $002d;
h_Y1:
    *= $002e;  difference
l_FF:
    *= $002f;
h_FF:
    *= $0030;  diff x
l_FX:
    *= $0031;
h_FX:
    *= $0032;  diff y
l_FY:
    *= $0033;
h_FY:
    *= $0034;
l_XY:
    *= $0035
h_XY:
    *= $0036
rCOL:

    *= $0600  ;
start:
  LDA #16;    Center low;
  STA l_XC;   XL = 16
  STA l_YC;   YL = 16
  LDA #0;     Center high
  STA h_XC;   XH = 00
  STA h_YC;   YH = 00
  STA hRAD;   RADH = 00
loop:
  LDA $fe ;   RND Radius low;
  AND #$0F;   A <= 15
  STA lRAD;   RND RADL = A <=15
  LDA $fe ;   A = RND;
  STA rCOL;   COLOR = RND;
  JSR CIRCLE; CIRCLE(XC,YC-lRAD)
  JMP loop;   jump CYCLE ;

; ----------------------------------
; CIRCLE: Draw a circle around the
; center XC/YC with radius in lRAD.
    *= $c000
CIRCLE:
  lda  lRAD     ; get Radius
  bne  _C1
  lda  l_XC    ; if lRAD=0, plot center point and exit
  sta  l_XP    ; move center point to plot point var
  lda  h_XC
  sta  h_XP
  lda  l_YC
  sta  l_YP
  lda  h_YC
  sta  h_YP
  jmp  PSET  ; Plot as a point and exit

;  int y = radius;
_C1:
  lda  lRAD    ; 8 bit radius - can be expanded to 16 bit
  sta  l_Y1
  ldx  #$00
  stx  h_Y1
; int  x = 0;
  stx  l_X1;
  stx  h_X1;
; if using 16 bit radius, this code
; section will need modifications
; int f = 1 - radius;
  sec
  lda  #$01
  sbc  lRAD
  sta  l_FF
  ldx  #$00
  stx  h_FF
  bcs  _C2
  dec  h_FF
; int ddF_x = 1;
_C2:
  lda  #$01
  sta  l_FX
  ldx  #$00
  stx  h_FX
; if using 16 bit radius, this code section
; will need modifications also
; int ddF_y = -2 * radius;
  stx  h_FY
  lda  lRAD
  asl      ; *2
  sta  l_FY
  rol  h_FY
  lda  l_FY
  EOR  #$FF
  sta  l_FY
  lda  h_FY
  EOR  #$FF
  sta  h_FY
  inc  l_FY
  bne  _C3
  inc  h_FY
;  tgi_setpixel(xC, yC + y);
_C3:
  lda  l_XC
  sta  l_XP
  lda  h_XC
  sta  h_XP
  clc
  lda  l_YC
  adc  l_Y1
  sta  l_YP
  lda  h_YC
  adc  h_Y1
  sta  h_YP
  jsr  PSET

;  tgi_setpixel(xC, yC - y);
  sec
  lda  l_YC
  sbc  l_Y1
  sta  l_YP
  lda  h_YC
  sbc  h_Y1
  sta  h_YP
  jsr  PSET

;  tgi_setpixel(xC + y, yC);
  clc
  lda  l_XC
  adc  l_Y1
  sta  l_XP
  lda  h_XC
  adc  h_Y1
  sta  h_XP
  lda  l_YC
  sta  l_YP
  lda  h_YC
  sta  h_YP
  jsr  PSET

;  tgi_setpixel(xC - y, yC);
  sec
  lda  l_XC
  sbc  l_Y1
  sta  l_XP
  lda  h_XC
  sbc  h_Y1
  sta  h_XP
  jsr  PSET

_CLOOP:
;  while (x < y) {    ; calculate next plot step
  sec
  lda  l_X1
  sbc  l_Y1
  lda  h_X1
  sbc  h_Y1
  bcc  _C4  ; x<y
  rts

_C4:
  lda  h_FF
  bmi  _C6

  lda  l_Y1
  bne  _C5
  dec  h_Y1
_C5:
  dec  l_Y1
  clc
  lda  l_FY
  adc  #$02
  sta  l_FY
  tax
  lda  h_FY
  adc  #$00
  sta  h_FY
  tay
  clc
  txa
  adc  l_FF
  sta  l_FF
  tya
  ADC  h_FF
  sta  h_FF

_C6:
  inc  l_X1
  bne  _C7
  inc  h_X1
_C7:
  clc
  lda  l_FX
  adc  #$02
  sta  l_FX
  tax
  lda  h_FX
  adc  #$00
  sta  h_FX
  tay
  clc
  txa
  adc  l_FF
  sta  l_FF
  tya
  ADC  h_FF
  sta  h_FF
; computations done - now plot 8 Octants

; tgi_setpixel(xC + x, yC + y);
  clc
  lda  l_XC
  adc  l_X1
  sta  l_XP
  pha
  lda  h_XC
  adc  h_X1
  sta  h_XP
  pha
  clc
  lda  l_YC
  adc  l_Y1
  sta  l_YP
  lda  h_YC
  adc  h_Y1
  sta  h_YP
  jsr  PSET

; tgi_setpixel(xC - x, yC + y);
  sec
  lda  l_XC
  sbc  l_X1
  sta  l_XP
  lda  h_XC
  sbc  h_X1
  sta  h_XP
  jsr  PSET

; tgi_setpixel(xC - x, yC - y);
  sec
  lda  l_YC
  sbc  l_Y1
  sta  l_YP
  lda  h_YC
  sbc  h_Y1
  sta  h_YP
  jsr  PSET

; tgi_setpixel(xC + x, yC - y);
  pla
  sta  h_XP
  pla
  sta  l_XP
  jsr  PSET

; tgi_setpixel(xC + y, yC + x);
  clc
  lda  l_XC
  adc  l_Y1
  sta  l_XP
  pha
  lda  h_XC
  adc  h_Y1
  sta  h_XP
  pha
  clc
  lda  l_YC
  adc  l_X1
  sta  l_YP
  lda  h_YC
  adc  h_X1
  sta  h_YP
  jsr  PSET

; tgi_setpixel(xC - y, yC + x);
  sec
  lda  l_XC
  sbc  l_Y1
  sta  l_XP
  lda  h_XC
  sbc  h_Y1
  sta  h_XP
  jsr  PSET

; tgi_setpixel(xC - y, yC - x);
  sec
  lda  l_YC
  sbc  l_X1
  sta  l_YP
  lda  h_YC
  sbc  h_X1
  sta  h_YP
  jsr  PSET

; tgi_setpixel(xC + x, yC - y);
  pla
  sta  h_XP
  pla
  sta  l_XP
  jsr  PSET
  jmp  _CLOOP

; ------------------------------------------------
; PSET: Test pixel @ XP,YP and plot it on screen
PSET:
  LDA l_YP
  ASL;      2* l_YP ;
  TAX;  X = 2* l_YP ;
  LDA offs,x
  INX
  CLC
  ADC l_XP
  STA l_XY
  LDA offs,x
  ADC #$02
  STA h_XY
  LDX #0
  LDA rCOL
  STA ($34,X)
  RTS
offs:
  dcb $00,$00
  dcb $20,$00
  dcb $40,$00
  dcb $60,$00
  dcb $80,$00
  dcb $a0,$00
  dcb $c0,$00
  dcb $e0,$00
  dcb $00,$01
  dcb $20,$01
  dcb $40,$01
  dcb $60,$01
  dcb $80,$01
  dcb $a0,$01
  dcb $c0,$01
  dcb $e0,$01
  dcb $00,$02
  dcb $20,$02
  dcb $40,$02
  dcb $60,$02
  dcb $80,$02
  dcb $a0,$02
  dcb $c0,$02
  dcb $e0,$02
  dcb $00,$03
  dcb $20,$03
  dcb $40,$03
  dcb $60,$03
  dcb $80,$03
  dcb $a0,$03
  dcb $c0,$03
  dcb $e0,$03
;------end-------------------------
И в результате работы этого кода получаются вот такие результаты: :wink:

------------Image
iLavr
petrenko
Doomed
Posts: 598
Joined: 10 Mar 2012 16:21
Location: РФ

Post by petrenko »

Lavr , мы внимательно следим за всем этим. :wink:

Как считаете, если организация экранной области идёт как бы "задом наперёд" по отношению к нашему старому доброму "Специалисту" ,то есть левая колонка 0FEFFh ,следующая 0FDFFh и т.д. на уменьшение по 256 байт на колонку ,то подойдёт алгоритм товарища Брезенхема и в таком случае , так ведь ?

Что там придётся изменить, в тексте для асм8080 не затруднит ли подчеркнуть.. :roll:
User avatar
Lavr
Supreme God
Posts: 16676
Joined: 21 Oct 2009 08:08
Location: Россия

Post by Lavr »

petrenko wrote:Как считаете, если организация экранной области идёт как бы "задом наперёд" по отношению к нашему старому доброму "Специалисту" ,то есть левая колонка 0FEFFh ,следующая 0FDFFh и т.д. на уменьшение по 256 байт на колонку ,то подойдёт алгоритм товарища Брезенхема и в таком случае , так ведь ?
Алгоритм Брезенхема подойдет в любом случае, поскольку он одинаков для всех организаций экрана,
он работает до экранных координат X и Y.
Ну а дальше должна быть конкретная реализация аппаратно-зависимой функции установки точки по
адресу в видео-ОЗУ - PLOT, PSET или PutPixel.

Здесь не очень много сказано про организацию. Но я так понимаю, что есть максимальный адрес начала
экрана и на каждые 8 бит по Х идет уменьшение на 265 байт по Y.
Я полагаю, что в функции PLOT после умножения на 32 результат надо вычитать от базового.
То есть дополнение до единицы и сложение с базовым - как-то так я представляю это.
iLavr
petrenko
Doomed
Posts: 598
Joined: 10 Mar 2012 16:21
Location: РФ

Post by petrenko »

Ага, как то так тоже подумал.

И я уточнял именно за реализацию, на асм для 8080 :idea:

И наверное есть варианты переделать модуль в адресно-независимый ( что вообще то для 8080 всегда было затруднением ).

Ну и быстродействие тоже важно для столь медленной системы, в этом смысле смущают в первую очередь CALL ,сразу хочется заменить их на макросы например.