آتاری ۲۶۰۰ که با نام Atari VCS در سال ۱۹۷۸ عرضه شد اولین کنسولی بود که از پروسسور ۶۵۰۲ استفاده میکرد و دومین کنسولی بود که از کارتریج به عنوان رسانه استفاده میکرد. به عبارتی ۲۶۰۰ الگوی کنسولهای مدرن بود. اما برنامه نویسی برای این کنسول به سادگی برنامه نویسی برای کنسولهای مدرن نیست. برای نوشتن یک بازی برای PS4 کافیست از یک انجین مثل آنریل، یونیتی یا گودو استفاده کنید. البته یک API Key لازم دارید تا انجین بتواند به شما اکسکیوتیبلهای کنسول را بدهد. انجینهای مدرن بازی سازی را تبدیل کرده اند به یک جهاد هنری تا یک جهاد برنامه نویسی. اما ۲۶۰۰ اصلا اینگونه نیست. در ۲۶۰۰ هشت کیلوبایت رم بیشتر نیست، یک سی پی یو با یک رجیستر اکولومیتر و دو رجیستر ایندکس و یک استک. و دو آی سی جانبی.
همراه ۲۶۰۰ هیچ راهنمایی نیست. این وظیفه ی برنامه نویس است که کنسول را مهندسی معکوس کند و ببیند داخل آن چه خبر است. و خیلی از برنامه نویس ها همین کار را کردند. برنامه نویسهایی که از Stella Guide خبر نداشتند.
در سال ۱۹۷۸ چندماه بعد از عرضه ی کنسول برنامه نویسی به نام استیو رایت آمد و Stella Guide را نوشت. این راهنما حاوی است از تمامی مشخصات کنسول تا بتوان با اسمبلی ۶۵۰۲ رجیسترهای لازمه را بارگذاری کرد تا کنسول کاری را که میخواهیم انجام دهد.
به گفته ی این راهنما ۲۶۰۰ یک فریم تلوزیون را به ۲۶۲ خط فرضی افقی تقسیم میکند که هر ۲۲۸ تعداد کلاک را بین هم تقسیم کرده اند. و این ۲۲۸ کلاک ۳.۵۸ مگاهرتز روی هم میگیرد. حالا میرسیم به VSYNC و VBLANK. یک فریم ۳ خط عمودی وی سینک دارد و ۳۷ خط عمودی وی بلنک. و ۱۹۲ خط که خود تصویر را رسم میکنند. هر اسکن لاین در NTSC سی خط اوراسکن دارد.
خط های افقی اتوماتیک کلاک میشوند یعنی دو آی سی که در مورد آنها صحبت خواهیم کرد وظیفه ی به کنترل گرفتن خطهای افقی را دارند. اما خط های عمودی با اسمبلی کنترل میشوند. اگر این روزها یک کراس اسمبلر ۲۶۰۰ پیدا کنید یک فرمان به نام VSYNC دارند. این فرمان تنها کاری که میکند رجیستر مخصوص وی سینک در پروسسور را پر میکند. اگر وی سینک true یا 0x11 باشد یعنی وی سینک را انجام بده.
حال به آی سی TIA میرسیم. نام این آی سی یعنی Television Interface Adapter. با وارد کردن دیتای هر خط عمودی در رجیستری چیپ TIA کنسول موفق به رسم یک خط میشود. فرض کنید TIA یک کارت گرافیک است. هر خط ۷۶ سایکل میکروپروسسور را میگیرد.اما نگران نباشید چون میکروپروسسو ۳.۵ مگاهرتز است و میتواند اینکار را انجام دهد.
اما ۳ خط وی سینک، ۳۷ خط وی بلنک، و ۳۰ خط اورسکن چه؟ اینها در TIA کار نمیکنند، یعنی TIA به آنها کاری ندارد و روی تلوزیون هم ترسیم نمیشوند. پس برای همین میتوان از ۵۳۲۰ سایکل باقیمانده ی این خطوط برای منطق بازی استفاده کرد.
به بخش پیوستها بروید تا دیاگرام این چیزهایی که توضیح داده ام را ببینید.
اینجاست که وارد محدودیتهای کنسول میشویم. کنسول میتوانید یک پس زمینه، یک محیط بازی، یک پلیر ۱ و یک پلیر ۲، یک موشک ۱ و یک موشک ۲ داشته باشد. گیج شده اید؟ تمام اشخاصی که برای ۲۶۰۰ در این روزها بازی مینویسند گیج میشوند. پس اسپرایت چه؟ پس هیت باکس چه؟ بدانید که ۲۶۰۰ چهل و سه سال پیش عرضه شده و در آن زمان بازیهایی مانند Space Invaders و Pac-Man هنوز این صنعت را معنی نداده بودند. پس مهندسان آتاری بر اساس بازیهایی مانند Pong و Tank این کنسول را طراحی کردند. من به این آبجکتها میگویم «آبجکتهای سبعه» (سبع یعنی هفت) اما شما هرچی خواستید بهش بگویید.
هر کدام از آبجکتهای سبعه رجیستر خودشان را در TIA دارند.
و کنترلر. هر دکمه ی کنترلر آدرس هکسادسیمال (شانزده شانزدهی) خودش را دارد. این آدرس آدرس حافظه میباشد. با زدن هر دکمه این آدرس ۰ یا۱ میشود یعنی دکمه زده شده یا نه. میتوان با اینستراکشن BNE این را چک کرد.
گفتم ۲۶۰۰ دو آی سی دارد. آی سی دیگر PIA است. این آی سی را برخلاف TIA که طراح آن MOS Technologies بوده، یک آی سی آماده است.
اطلاعات بیشتر را میتوانید در راهنمای استلا پیدا کنید.
در اخر میخواهم کد بازی پانگ که تنها ۲۵۶ بایت است و برای این کنسول در دهه ی نود توسط یک آدم خوش ذوق نوشته شده به اشتراک بگذارم:
همراه ۲۶۰۰ هیچ راهنمایی نیست. این وظیفه ی برنامه نویس است که کنسول را مهندسی معکوس کند و ببیند داخل آن چه خبر است. و خیلی از برنامه نویس ها همین کار را کردند. برنامه نویسهایی که از Stella Guide خبر نداشتند.
در سال ۱۹۷۸ چندماه بعد از عرضه ی کنسول برنامه نویسی به نام استیو رایت آمد و Stella Guide را نوشت. این راهنما حاوی است از تمامی مشخصات کنسول تا بتوان با اسمبلی ۶۵۰۲ رجیسترهای لازمه را بارگذاری کرد تا کنسول کاری را که میخواهیم انجام دهد.
به گفته ی این راهنما ۲۶۰۰ یک فریم تلوزیون را به ۲۶۲ خط فرضی افقی تقسیم میکند که هر ۲۲۸ تعداد کلاک را بین هم تقسیم کرده اند. و این ۲۲۸ کلاک ۳.۵۸ مگاهرتز روی هم میگیرد. حالا میرسیم به VSYNC و VBLANK. یک فریم ۳ خط عمودی وی سینک دارد و ۳۷ خط عمودی وی بلنک. و ۱۹۲ خط که خود تصویر را رسم میکنند. هر اسکن لاین در NTSC سی خط اوراسکن دارد.
خط های افقی اتوماتیک کلاک میشوند یعنی دو آی سی که در مورد آنها صحبت خواهیم کرد وظیفه ی به کنترل گرفتن خطهای افقی را دارند. اما خط های عمودی با اسمبلی کنترل میشوند. اگر این روزها یک کراس اسمبلر ۲۶۰۰ پیدا کنید یک فرمان به نام VSYNC دارند. این فرمان تنها کاری که میکند رجیستر مخصوص وی سینک در پروسسور را پر میکند. اگر وی سینک true یا 0x11 باشد یعنی وی سینک را انجام بده.
حال به آی سی TIA میرسیم. نام این آی سی یعنی Television Interface Adapter. با وارد کردن دیتای هر خط عمودی در رجیستری چیپ TIA کنسول موفق به رسم یک خط میشود. فرض کنید TIA یک کارت گرافیک است. هر خط ۷۶ سایکل میکروپروسسور را میگیرد.اما نگران نباشید چون میکروپروسسو ۳.۵ مگاهرتز است و میتواند اینکار را انجام دهد.
اما ۳ خط وی سینک، ۳۷ خط وی بلنک، و ۳۰ خط اورسکن چه؟ اینها در TIA کار نمیکنند، یعنی TIA به آنها کاری ندارد و روی تلوزیون هم ترسیم نمیشوند. پس برای همین میتوان از ۵۳۲۰ سایکل باقیمانده ی این خطوط برای منطق بازی استفاده کرد.
به بخش پیوستها بروید تا دیاگرام این چیزهایی که توضیح داده ام را ببینید.
اینجاست که وارد محدودیتهای کنسول میشویم. کنسول میتوانید یک پس زمینه، یک محیط بازی، یک پلیر ۱ و یک پلیر ۲، یک موشک ۱ و یک موشک ۲ داشته باشد. گیج شده اید؟ تمام اشخاصی که برای ۲۶۰۰ در این روزها بازی مینویسند گیج میشوند. پس اسپرایت چه؟ پس هیت باکس چه؟ بدانید که ۲۶۰۰ چهل و سه سال پیش عرضه شده و در آن زمان بازیهایی مانند Space Invaders و Pac-Man هنوز این صنعت را معنی نداده بودند. پس مهندسان آتاری بر اساس بازیهایی مانند Pong و Tank این کنسول را طراحی کردند. من به این آبجکتها میگویم «آبجکتهای سبعه» (سبع یعنی هفت) اما شما هرچی خواستید بهش بگویید.
هر کدام از آبجکتهای سبعه رجیستر خودشان را در TIA دارند.
و کنترلر. هر دکمه ی کنترلر آدرس هکسادسیمال (شانزده شانزدهی) خودش را دارد. این آدرس آدرس حافظه میباشد. با زدن هر دکمه این آدرس ۰ یا۱ میشود یعنی دکمه زده شده یا نه. میتوان با اینستراکشن BNE این را چک کرد.
گفتم ۲۶۰۰ دو آی سی دارد. آی سی دیگر PIA است. این آی سی را برخلاف TIA که طراح آن MOS Technologies بوده، یک آی سی آماده است.
اطلاعات بیشتر را میتوانید در راهنمای استلا پیدا کنید.
در اخر میخواهم کد بازی پانگ که تنها ۲۵۶ بایت است و برای این کنسول در دهه ی نود توسط یک آدم خوش ذوق نوشته شده به اشتراک بگذارم:
Code:
; SMALLPONG v2.1 (255 bytes)
; Brad Smith
; 6/29/2008
; 16-bit instruction set, begin at 100h
use16
org 100h
; constants
SCREEN_WIDTH = 320
SCREEN_HEIGHT = 200
SCREEN_X_MID = SCREEN_WIDTH / 2
SCREEN_Y_MID = SCREEN_HEIGHT / 2
SCREEN_SIZE = SCREEN_WIDTH * SCREEN_HEIGHT
PADDLE_SIZE = 10
;PADDLE_LEFT_X = 0
PADDLE_RIGHT_X = SCREEN_WIDTH - 1
PADDLE_TOP = 1
PADDLE_MID = SCREEN_Y_MID - (PADDLE_SIZE/2)
PADDLE_BOTTOM = (SCREEN_HEIGHT-1) - PADDLE_SIZE
BALL_MID_X = SCREEN_X_MID
BALL_MID_Y = SCREEN_Y_MID
BALL_TOP = PADDLE_TOP
BALL_BOTTOM = (PADDLE_BOTTOM + PADDLE_SIZE) - 1
AI_THRESHOLD = SCREEN_WIDTH - 90
; main program
start:
; set up VGA mode 13h
mov al, 013h
int 10h
; store video register in es (will stay constant from here on)
push word 0A000h
pop es
; clear the screen
;xor di, di ; di = 0
;mov cx, SCREEN_SIZE
;xor al, al ; al = 0
;repz stosb
; setup stack
push word PADDLE_MID
push word BALL_MID_X
push word BALL_MID_Y
game_loop:
; wait for vsync
vsync_active:
mov dx, 03DAh ; input status port for checking retrace
in al, dx
test al, 8
jnz vsync_active ; Bit 3 on signifies activity
vsync_retrace:
in al, dx
test al, 8
jz vsync_retrace ; Bit 3 off signifies retrace
; draw game part 1
; clear old ball
; STACK: ball_y, ball_x, paddle_left_y
pop ax ; STACK: ball_x, paddle_left_y
pop bx ; STACK: paddle_left_y
xor dl, dl ; dl = 0
call put_pixel
; update game state part
; right paddle AI
; bx = ball_x
cmp bx, AI_THRESHOLD
mov cx, bx ; move bal_x to cx
mov bx, [paddle_right_y]
jl skip_ai
; ax = ball_y
sub al, (PADDLE_SIZE / 2)
cmp ax, bx
je end_ai
jg ai_dn
;ai_up:
dec bx
jmp end_ai
ai_dn:
inc bx
end_ai:
add al, (PADDLE_SIZE / 2)
skip_ai:
call clamp_paddle
mov [paddle_right_y], bx
; move ball vertical
; ax = ball_y
add al, [ball_dy]
; mov [ball_y], ax
; bounce vertical
cmp al, BALL_TOP
jne ball_not_top
neg byte [ball_dy]
ball_not_top:
cmp al, BALL_BOTTOM
jne ball_not_bottom
neg byte [ball_dy]
ball_not_bottom:
; move ball horizontal
add cx, [ball_dx]
; check for right paddle collision / goal
; ax = ball_y
; bx = paddle_right_y
; cx = ball_x
mov dx, PADDLE_RIGHT_X
call collide_paddle
; left paddle moved by player
pop bx ; STACK: EMPTY
; get movement state
push ax ; STACK: ball_y
; get shift registers
mov ah, 02h
int 16h
; test for CTRL
test al, 4
jz no_ctrl
inc bx ; move paddle down
no_ctrl:
; test for ALT
test al, 8
jz no_alt
dec bx ; move paddle up
no_alt:
pop ax ; STACK: EMPTY
call clamp_paddle
push bx ; STACK: paddle_left_y
; check for left paddle collision / goal
; ax = ball_y
; bx = paddle_left
xor dx, dx ; dx = PADDLE_LEFT_X
call collide_paddle
; end update game state
; draw game part 2
; draw ball
; ax = ball_y
xchg bx, cx ; bx = ball_x, cx = paddle_left_y
mov dl, 15
call put_pixel
push bx ax ; STACK: ball_x, ball_y, paddle_left_y
; draw left paddle
mov ax, cx ; ax = paddle_left_y
xor bx, bx ; bx = PADDLE_LEFT_X
call draw_paddle
; draw right paddle
mov ax, [paddle_right_y]
mov bx, PADDLE_RIGHT_X
mov dl, 15
call draw_paddle
; end draw game part 2
; continue game if no regular keypresses
mov ah, 1
int 16h
jz game_loop
; [ 2 bytes ]
; exit if a key has been pressed
int 20h
; global data
screen_width: dw SCREEN_WIDTH
paddle_right_y: dw PADDLE_MID
ball_dx: dw 1
ball_dy: db -1
; subroutines
; put_pixel
; plots a pixel at bx,ax with color dl
; (registers preserved)
put_pixel:
push ax bx dx
mul word [screen_width]
add bx, ax
pop dx
mov [es:bx], dl
pop bx ax
ret
; draw_paddle
; draws a paddle (position: bx,ax colour: dl)
draw_paddle:
mov cx, PADDLE_SIZE
draw_paddle_loop:
call put_pixel
inc ax
loop draw_paddle_loop
xor dl, dl ; dl = 0
call put_pixel
sub al, PADDLE_SIZE+1
call put_pixel
ret
; clamp_paddle
; clamps bx to [PADDLE_TOP,PADDLE_BOTTOM]
clamp_paddle:
cmp bl, PADDLE_TOP - 1
jne not_top
mov bl, PADDLE_TOP
not_top:
cmp bl, PADDLE_BOTTOM + 1
jne not_bottom
mov bl, PADDLE_BOTTOM
not_bottom:
ret
; collide_paddle
; collides paddle with ball
; ax = ball_y
; bx = paddle_y
; cx = ball_x
; dx = PADDLE_X
collide_paddle:
cmp cx, dx
jne no_collide
cmp ax, bx
jl new_ball
push bx
add bl, PADDLE_SIZE
cmp ax, bx
pop bx
jge new_ball
neg word [ball_dx]
ret
new_ball:
; "randomize" ball_x
add al, 97
and ax, 127
add ax, BALL_MID_Y - 64
mov cx, BALL_MID_X
; don't bother resetting ball_dx/dy
; just send ball to player who just lost
no_collide:
ret
; END OF FILE
; Brad Smith, 2008