SPO600 LAB 2 – انیمیشن در صفحه نمایش bitmap

مقدمه
خوش آمدید ، بیایید با 6502 مونتاژ بیشتر ادامه دهیم. در آخرین پست وبلاگ ، صفحه نمایش Bitmap معرفی شد و پر از رنگ های مختلف خواهد بود. از آن کشف شد که صفحه نمایش Bitmap از صفحه 2 به صفحه 5 (یعنی $0200 - $0500
).
امروز یک تصویر از طریق صفحه نمایش bitmap متحرک می شود. در زیر کد استارت ارائه شده توسط کریس تایلر ، مربی دوره SPO600 ارائه شده است. ما به استفاده از شبیه ساز 6502 ادامه خواهیم داد.
;
; draw-image-subroutine.6502
;
; This is a routine that can place an arbitrary
; rectangular image on to the screen at given
; coordinates.
;
; Chris Tyler 2024-09-17
; Licensed under GPLv2+
;
;
; The subroutine is below starting at the
; label "DRAW:"
;
; Test code for our subroutine
; Moves an image diagonally across the screen
; Zero-page variables
define XPOS $20
define YPOS $21
START:
; Set up the width and height elements of the data structure
LDA #$05
STA $12 ; IMAGE WIDTH
STA $13 ; IMAGE HEIGHT
; Set initial position X=Y=0
LDA #$00
STA XPOS
STA YPOS
; Main loop for diagonal animation
MAINLOOP:
; Set pointer to the image
; Use G_O or G_X as desired
; The syntax #
کد استارت یک دایره آبی را در گوشه سمت چپ بالای صفحه نمایش Bitmap متحرک می کند و سپس آن را به صورت مورب به گوشه پایین سمت راست منتقل می کند و به طور نامحدود تکرار می شود. برای درک چگونگی عملکرد این کار ، بیایید هر روال/زیرروال را تجزیه کنیم و سپس نحوه کار آنها را توضیح دهیم.
تنظیم اولیه
متغیرهای صفحه صفر
; Zero-page variables
define XPOS $20
define YPOS $21
define
یک کلمه کلیدی خاص است که ثابت را تعریف می کند. در این حالت ، XPOS
وت YPOS
مکان های حافظه مربوطه را برای مختصات تصویر نشان می دهد.
تنظیم موضع
START:
LDA #$05
STA $12 ; IMAGE WIDTH
STA $13 ; IMAGE HEIGHT
LDA #$00
STA XPOS
STA YPOS
تصویر ابعاد دارد 5x5
و مختصات اولیه از 0,0
، گوشه سمت چپ بالای صفحه نمایش Bitmap.
حلقه انیمیشن اصلی
MAINLOOP:
LDA #<G_O
STA $10
LDA #>G_O
STA $11
حلقه های اصلی انیمیشن آدرس تصویر را در باتری بار می کند و سپس بایت کم و بالا و پایین خود را در مکان های حافظه ذخیره می کند $10
وت $11
به ترتیب
; Place the image on the screen
LDA #$10 ; Address in zeropage of the data structure
LDX XPOS ; X position
LDY YPOS ; Y position
JSR DRAW ; Call the subroutine
بایت کم تصویر در مختصات x و y بارگذاری شده است – اینجاست DRAW
Subroutine شروع به ترسیم تصویر به صفحه نمایش Bitmap می کند.
تاخیر
LDY #$00
LDX #$50
DELAY:
DEY
BNE DELAY
DEX
BNE DELAY
در DELAY
روال کند می شود DRAW
روال برای نمایش یک تصویر “جامد”. بدون DELAY
، تصویر به سرعت چشمک می زند. 2 حلقه وجود دارد – یک حلقه بیرونی که 256 بار y را افزایش می دهد ، و یک حلقه داخلی که 80 بار کاهش می یابد. در مجموع 80 * 256 = 20480
تکرارها
متحرک تصویر
; Set pointer to the blank graphic
LDA #<G_BLANK
STA $10
LDA #>G_BLANK
STA $11
; Draw the blank graphic to clear the old image
LDA #$10
LDX XPOS
LDY YPOS
JSR DRAW
; Increment the position
INC XPOS
INC YPOS
LDA #28
CMP XPOS
BNE MAINLOOP
...
; Image of a black square
G_BLANK:
DCB $00,$00,$00,$00,$00
DCB $00,$00,$00,$00,$00
DCB $00,$00,$00,$00,$00
DCB $00,$00,$00,$00,$00
DCB $00,$00,$00,$00,$00
برای “تحریک” تصویر ، تصویر فعلی با جایگزینی تصویر با پیکسل های سیاه “خالی” می شود. بایت کم سپس در باتری بارگیری می شود ، موقعیت x و y تصویر در ثبت های مربوطه در جایی که افزایش می یابد بارگیری می شود. تصویر در موقعیت X ، Y جدید خود ترسیم می شود – تکمیل انیمیشن. پس از 29 “حرکات” و سپس همان انیمیشن به طور نامحدود تکمیل می شود.
DRAW
زیرروال
در DRAW
Subroutine مهمترین قسمت برنامه است – محاسبه می کند که در هر تکرار تصویر در کجا می رود.
define IMGPTR $A0
define IMGPTRH $A1
define IMGWIDTH $A2
define IMGHEIGHT $A3
define SCRPTR $A4
define SCRPTRH $A5
define SCRX $A6
define SCRY $A7
...
DRAW:
STY SCRY
STX SCRX
TAY
LDA $0000,Y
STA IMGPTR
LDA $0001,Y
STA IMGPTRH
LDA $0002,Y
STA IMGWIDTH
LDA $0003,Y
STA IMGHEIGHT
این کار با بارگیری موقعیت مرزهای صفحه و خصوصیات تصویر (مختصات X ، Y ، ارتفاع و عرض) از آدرس های حافظه مربوطه شروع می شود و آنها را در آدرس های ثبت نام از پیش تعریف شده ذخیره می کند – این مقادیر بعداً هنگام محاسبه موقعیت به آنها دسترسی پیدا می کنند برای تصویر بعدی
محاسبه موقعیت صفحه نمایش
LDA #$00
STA SCRPTRH
LDA SCRY
STA SCRPTR
LDY #$05
MULT:
ASL SCRPTR
ROL SCRPTRH
DEY
BNE MULT
مراحل محاسبه:
- باتری را پاک کنید ، اینجاست که محاسبه انجام می شود
- باتری را با هماهنگی Y تصویر بارگیری کنید
-
هماهنگ y سپس با آن بارگیری می شود
5
تعداد شیفت ها برای حرکت پیکسل از آنجا که هر ردیف 32 بایت طول دارد.1 | 2 | 4 | 8 | 16 | 32 ^ | 2 | 3 | 4 | 5 | 6 current
-
در
MULT
روتین بیت ها را به سمت چپ تغییر می دهدASL
وتROL
حمل را به داخل می چرخاندSCRPTRH
، رجیستری Y سپس کاهش می یابد و تا y = 0 تکرار می شود.
LDA SCRX
CLC
ADC SCRPTR
STA SCRPTR
LDA #$00
ADC SCRPTRH
STA SCRPTRH
- محاسبه هماهنگ X علاوه بر این – جایی که بایت کم اضافه می شود و به دنبال بایت بالا اضافه می شود. در
ADC SCRPTR
بایت کم را با حمل به باتری اضافه می کند. این مقدار حمل سپس با حمل بایت بالا اضافه می شود. - در این مرحله ،
SCRPTR
وتSCRPTRH
آدرس های نهایی را برای تصویر تبدیل شده نگه دارید.
درج تصویر تبدیل شده
LDA #$02
CLC
ADC SCRPTRH
STA SCRPTRH
آدرس پایه نمایش bitmap از 02
بارگذاری شده است ، با پرچم حمل پاک شده است. نشانگر صفحه نمایش بایت بالا با اضافه کردن تنظیم می شود SCRPTRH
در آخرین مرحله محاسبه می شود.
COPYROW:
LDY #$00
ROWLOOP:
LDA (IMGPTR),Y
STA (SCRPTR),Y
INY
CPY IMGWIDTH
BNE ROWLOOP
بایت ها از IMGPTR
به باتری ، سپس به SCRPTR
که حافظه مربوط به مکان در صفحه نمایش bitmap است. حلقه متوقف می شود وقتی ثبت Y به انتهای ردیف تصویر می رسد.
LDA IMGWIDTH
CLC
ADC IMGPTR
STA IMGPTR
LDA #$00
ADC IMGPTRH
STA IMGPTRH
LDA #32
CLC
ADC SCRPTR
STA SCRPTR
LDA #$00
ADC SCRPTRH
STA SCRPTRH
برای پیشرفت به ردیف بعدی ، عرض تصویر در باتری بارگذاری می شود. IMGPTR
سپس به عرض تصویر اضافه می شود و ردیف بعدی را در تصویر پیش می برد. نشانگر تصویر به روز شده در آن ذخیره می شود IMGPTR
بشر 32
توسط اضافه شده به SCRPTR
در باتری پس از آن دوباره به داخل ذخیره می شود SCRPTR
بشر همان فرآیندها با بایت بالا ، با بایت حمل انجام می شود.
بیایید با تغییر موقعیت شروع شروع کنیم. با بارگیری باتری با مقادیر مختلف و ذخیره آن در XPOS
وت YPOS
بشر
START:
LDA #$05
STA $12 ; IMAGE WIDTH
STA $13 ; IMAGE HEIGHT
LDA #$0F
STA XPOS
LDA #$0A
STA YPOS
بعد بیایید وقتی با دیوار صفحه نمایش bitmap تماس برقرار کنیم ، گزاف گویی گرافیکی را انجام دهیم. برای انجام این کار ما می توانیم علامت را معکوس کنیم (به عنوان مثال +/-
) از جهت x و y هنگامی که گرافیک با دیوار تماس می گیرد.
برای انجام این کار بیایید یک مقدار ثابت را برای نشان دادن لبه صفحه تعریف کنیم:
; Zero-page variables
define XPOS $20
define YPOS $21
define MAXP $24
در مرحله بعد ما باید جهت تصویر را ردیابی کنیم ، آیا آن “به جلو” یا “به عقب” حرکت می کند؟ در این مورد “به عقب” حرکت می کند ، جهت می تواند معکوس شود و برعکس.
; Zero-page variables
define XPOS $20
define YPOS $21
define MAXP $24
define CURDIR $25
علامت X و Y نیز نیاز به ردیابی دارند تا بدانند محورهای مربوطه برای حرکت به چه جهت نیاز دارند.
; Zero-page variables
define XPOS $20
define YPOS $21
define MAXP $22
define CURDIR $23
define XFLAG $24
define YFLAG $25
ما متغیرهای لازم را ردیابی می کنیم ، اکنون بیایید منطق معکوس کردن علامت را هنگام رسیدن به لبه پیاده سازی کنیم.
ابتدا بیایید اولیه کنیم CURDIR
برای داشتن یک ارزش 0
برای نشان دادن جهت رو به جلو و MAXP
#$19
، لبه صفحه.
START:
LDA #$00
STA CURDIR
LDA #$19
STA MAXP
بعد بیایید پرونده ای را که تصویر با یک زیرروال به لبه برخورد می کند ، پیاده سازی کنیم:
- مقدار مربوط به لبه را بارگیری کنید
- جریان را مقایسه کنید
XPOS
با مقدار لبه - فراخوانی
CHECK_START
برای بررسی اینکه از گوشه سمت چپ بالا برخورد کرده است- از آنجا که علائم معکوس هستند ، با توجه به موقعیت شروع جدید ، همیشه به گوشه سمت چپ می رسد.
CHECK_DIRECTION:
LDA MAXP
CMP XPOS
BNE CHECK_START
CHECK_START:
LDA XPOS
CMP #$00
BNE CONTINUE_LOOP
LDA #$00
STA CURDIR
CONTINUE_LOOP
بررسی می کند که آیا انیمیشن به پایان رسیده است و آن را به طور نامحدود تکرار می کند. بیایید کد را با هم نگاه کنیم.
;
; draw-image-subroutine.6502
;
; This is a routine that can place an arbitrary
; rectangular image on to the screen at given
; coordinates.
;
; Chris Tyler 2024-09-17
; Licensed under GPLv2+
;
;
; The subroutine is below starting at the
; label "DRAW:"
;
; Test code for our subroutine
; Moves an image diagonally across the screen
; Zero-page variables
define XPOS $20
define YPOS $21
define MAXP $22
define CURDIR $23
define XFLAG $24
define YFLAG $25
START:
LDA #$00
STA CURDIR
LDA #$19
STA MAXP
; Set up image width & height
LDA #$05
STA $12
STA $13
; Set initial position X=Y=0
LDA #$09
STA XPOS
LDA #$0A
STA YPOS
MAINLOOP:
; Set pointer to the image
LDA #<G_O
STA $10
LDA #>G_O
STA $11
; Put image on bitmap display
LDA #$10
LDX XPOS
LDY YPOS
JSR DRAW
; Delay to show the image
LDY #$00
LDX #$50
DELAY:
DEY
BNE DELAY
DEX
BNE DELAY
; Put pointer to blank image
LDA #<G_BLANK
STA $10
LDA #>G_BLANK
STA $11
; Clear previous image position
LDA #$10
LDX XPOS
LDY YPOS
JSR DRAW
LDA CURDIR
BEQ INCREMENT_POS
DEC XPOS
DEC YPOS
JMP CHECK_DIRECTION
INCREMENT_POS:
INC XPOS
INC YPOS
CHECK_DIRECTION:
LDA MAXP
CMP XPOS
BNE CHECK_START
LDA XPOS
STA CURDIR
JMP CONTINUE_LOOP
CHECK_START:
LDA XPOS
CMP #$00
BNE CONTINUE_LOOP
LDA #$00
STA CURDIR
CONTINUE_LOOP:
LDA #28
CMP XPOS
BNE MAINLOOP
; Repeat infinitely
JMP START
; ==========================================
;
; DRAW :: Subroutine to draw an image on
; the bitmapped display
;
; Entry conditions:
; A - location in zero page of:
; a pointer to the image (2 bytes)
; followed by the image width (1 byte)
; followed by the image height (1 byte)
; X - horizontal location to put the image
; Y - vertical location to put the image
;
; Exit conditions:
; All registers are undefined
;
; Zero-page memory locations
define IMGPTR $A0
define IMGPTRH $A1
define IMGWIDTH $A2
define IMGHEIGHT $A3
define SCRPTR $A4
define SCRPTRH $A5
define SCRX $A6
define SCRY $A7
DRAW:
; SAVE THE X AND Y REG VALUES
STY SCRY
STX SCRX
; GET THE DATA STRUCTURE
TAY
LDA $0000,Y
STA IMGPTR
LDA $0001,Y
STA IMGPTRH
LDA $0002,Y
STA IMGWIDTH
LDA $0003,Y
STA IMGHEIGHT
; CALCULATE THE START OF THE IMAGE ON
; SCREEN AND PLACE IN SCRPTRH
;
; THIS IS $0200 (START OF SCREEN) +
; SCRX + SCRY * 32
;
; WE'LL DO THE MULTIPLICATION FIRST
; START BY PLACING SCRY INTO SCRPTR
LDA #$00
STA SCRPTRH
LDA SCRY
STA SCRPTR
; NOW DO 5 LEFT SHIFTS TO MULTIPLY BY 32
LDY #$05 ; NUMBER OF SHIFTS
MULT:
ASL SCRPTR ; PERFORM 16-BIT LEFT SHIFT
ROL SCRPTRH
DEY
BNE MULT
; NOW ADD THE X VALUE
LDA SCRX
CLC
ADC SCRPTR
STA SCRPTR
LDA #$00
ADC SCRPTRH
STA SCRPTRH
; NOW ADD THE SCREEN BASE ADDRESS OF $0200
; SINCE THE LOW BYTE IS $00 WE CAN IGNORE IT
LDA #$02
CLC
ADC SCRPTRH
STA SCRPTRH
; NOTE WE COULD HAVE DONE TWO: INC SCRPTRH
; NOW WE HAVE A POINTER TO THE IMAGE IN MEM
; COPY A ROW OF IMAGE DATA
COPYROW:
LDY #$00
ROWLOOP:
LDA (IMGPTR),Y
STA (SCRPTR),Y
INY
CPY IMGWIDTH
BNE ROWLOOP
; NOW WE NEED TO ADVANCE TO THE NEXT ROW
; ADD IMGWIDTH TO THE IMGPTR
LDA IMGWIDTH
CLC
ADC IMGPTR
STA IMGPTR
LDA #$00
ADC IMGPTRH
STA IMGPTRH
; ADD 32 TO THE SCRPTR
LDA #32
CLC
ADC SCRPTR
STA SCRPTR
LDA #$00
ADC SCRPTRH
STA SCRPTRH
; DECREMENT THE LINE COUNT AND SEE IF WE'RE
; DONE
DEC IMGHEIGHT
BNE COPYROW
RTS
; ==========================================
; 5x5 pixel images
; Image of a blue "O" on black background
G_O:
DCB $00,$0e,$0e,$0e,$00
DCB $0e,$00,$00,$00,$0e
DCB $0e,$00,$00,$00,$0e
DCB $0e,$00,$00,$00,$0e
DCB $00,$0e,$0e,$0e,$00
; Image of a yellow "X" on a black background
G_X:
DCB $07,$00,$00,$00,$07
DCB $00,$07,$00,$07,$00
DCB $00,$00,$07,$00,$00
DCB $00,$07,$00,$07,$00
DCB $07,$00,$00,$00,$07
; Image of a black square
G_BLANK:
DCB $00,$00,$00,$00,$00
DCB $00,$00,$00,$00,$00
DCB $00,$00,$00,$00,$00
DCB $00,$00,$00,$00,$00
DCB $00,$00,$00,$00,$00
منطق آزمایشگاه ساده است ، اما اجرای آن به دلیل چگونگی کلامی مونتاژ دشوار است. ماهیت کلامی مونتاژ باعث شده است که من از زبانهای سطح بالا قدردانی کنم و چقدر پنهان است.
از آزمایشگاه ، من در مورد موارد استفاده برای زیرمجموعه ها ، نحوه و زمان اجرای زیرروه ها در کارهای روزمره ، و BNE
بیانیه ها این شبیه به استفاده از حلقه های “برای” و اظهارات “if” در زبان های برنامه نویسی سطح بالا است.
به طور کلی ، من با این آزمایشگاه دوران سختی داشتم اما به روشی خوب – من آنچه را که در مورد مونتاژ تا این مرحله فهمیدم سؤال کردم و مهارت های تحلیل خود را به چالش کشیدم ، یک مهارت قابل انتقال که فراتر از کد مونتاژ است. با تشکر از خواندن! به زودی می بینیم!