نوشتن تقويم ( اسمبلي )

hobab1987

Member
سلام
من بايد تقويم بهار امسال رو بنويسم به هر سه تاريخ مجزاي(شمسي قمري ميلادي) و روزهاي تعطيل رنگي.
اسمبلي هم ساختار if و for رو بهمون ياد دادن.
نمي دونم چه طوري شروع به نوشتن كنم و چه چيزي لازمه!!
لطفا راهنماييم كنيد!
 
آخرین ویرایش:

the_king

مدیرکل انجمن
سلام
من بايد تقويم بهار امسال رو بنويسم به هر سه تاريخ مجزاي(شمسي قمري ميلادي) و روزهاي تعطيل رنگي.
اسمبلي هم ساختار if و for رو بهمون ياد دادن.
نمي دونم چه طوري شروع به نوشتن كنم و چه چيزي لازمه!!
لطفا راهنماييم كنيد!

بهار 3 ماه 31 روزه داره پس بایستی 93 روز رو نمایش دهید. 93 عدد بزرگی نیست پس متغیر های یک بایتی (DB)
هم کفایت می کنه.

حالا متغیر ها و آرایه هایی رو بررسی کنیم که لازم دارید :
1) متغیری که از روز اول (0) شروع بشه و تا آخرین روز (92) رو پیمایش کنه، اندیس ها اصولا در اسمبلی از
0 شروع می شوند، نه از 1 ، فرض کنیم که اسم این متغیر را day بگذاریم.

2) آرایه ای که مشخص کنه که امروز تعطیل است و یا امروز پایان ماه میلادی هست یا امروز پایان ماه قمری است.
برای هر روز یک بایت را در نظر می گیریم، پس این آرایه 93 بایتی است. مثلا سه بیت از این بایت ها را به
سه مورد مشخص شده اختصاص می دهیم. مثلا اگر بیت اول 1 بود یعنی روز تعطیل. اگر بیت دوم 1 بود
یعنی پایان ماه میلادی است و اگر بیت سوم 1 بود یعنی پایان ماه قمری است.
مقادیر این آرایه را در ابتدای برنامه باید وارد کنیم، اکثر مقادیر 0 است، چون نه تعطیل اند و نه پایان ماه های قمری
و شمسی اند.
فرض کنیم که اسم این آرایه را dmap بگذاریم.

3) متغیری که مشخص کنه که day چه ماه شمسی است، شروع اش هم 1 است، فرض کنیم که اسم این
متغیر را pmonth بگذاریم.

4) متغیری که مشخص کنه که day چه روزی از ماه شمسی است، شروع اش هم 1 است، هر زمان که از
31 بیشتر شد مجددا 1 می شود و مقدار pmount یک واحد افزایش می یابد، فرض کنیم که اسم این متغیر را
pday بگذاریم.

5) متغیری که مشخص کنه که day چه ماه میلادی است، شروع اش هم از 3 (March) است. فرض کنیم که اسم
این متغیر را gmonth بگذاریم.

6) متغیری که چه روزی از ماه میلادی است، شروع اش هم 21 است، هر زمان که dmap نشان داد پایان ماه
میلادی است، مجددا 1 می شود و مقدار gmount یک واحد افزایش می یابد، فرض کنیم که اسم
این متغیر را gday بگذاریم.

7) متغیری که مشخص می کنه که day چه ماه قمری است، شروع اش هم از 3 (ربیع الاول) است. فرض کنیم
که اسم این متغیر را imonth بگذاریم.

8) متغیری که مشخص کنه که day چه روزی از ماه قمری است، شروع اش هم 23 است، هر زمان
که dmap نشان داد پایان ماه قمری است، مجددا 1 می شود و مقدار imount یک واحد افزایش می یابد، فرض کنیم که اسم این متغیر را iday بگذاریم.

این متغیر های اصلی کار بود که به آنها نیاز دارید، مقدار day و pday و gday و iday را در حلقه 1 واحد افزایش خواهید
داد و بر اساس مقدار [dmap[day روزهای تعطیل و پایان ماه های قمری و میلادی را مشخص می کنید.
همچنین هر روز را با توجه به مقادیر متغیر ها در داخل حلقه چاپ خواهید کرد.
 

hobab1987

Member
خيلي ممنون king
تاحدودي سرنخ به دستم اومد بايد بيشتر دقت كنم رو نوشته هاتون ، تازه كارم ديگه اگر سوالم پيش پاافتاده بود معذرت ميخوام!
طرح كلي تقويم رو اينجوري در نظر گرفتم خوبه؟سخت نميشه؟!بهتر از اين ميشه؟!
اول يك صفحه main دارم كه1 رو ميزنم تقويم شمسي ظاهر ميشه به اين صورت:
كل روزهاي فروردين ليست ميشه يه كليد ميزنم روزهاي ارديبهت ليست ميشه و همچنين بعد خرداد

فروردين 88

شنبه 1شنبه 2شنبه ...
1 .......2 .......3......
8 .......9 ......10 ...
.. .. ...
اين رو نوشتم كه شنبه چاپ بشه اما 1 error داد نميدونم چرا؟!!:-?
کد:
[SIZE=2]stacksg segment stack 'stack'[/SIZE]
[SIZE=2]stacksg ends[/SIZE]
[SIZE=2]datasg segment 'data'[/SIZE]
[SIZE=2]a DB 'saturday','$'[/SIZE]
[SIZE=2]b DB 'Sunday','$'[/SIZE]
[SIZE=2]c DB 'Monday','$'[/SIZE]
[SIZE=2]d DB 'Tuesday','$'[/SIZE]
[SIZE=2]e DB 'Wednesday','$'[/SIZE]
[SIZE=2]f DB 'Thursday','$'[/SIZE]
[SIZE=2]g DB 'Friday','$'[/SIZE]
[SIZE=2]datasg ends[/SIZE]
[SIZE=2]codsg segment 'code'[/SIZE]
[SIZE=2]assume: ss:stacksg, ds:datasg, cs:codsg[/SIZE]
[SIZE=2]main proc near [/SIZE]
[SIZE=2]mov AX, datasg[/SIZE]
[SIZE=2]mov DX, ax[/SIZE]
[SIZE=2]mov AH, 06h[/SIZE]
[SIZE=2]int 10h[/SIZE]
[SIZE=2]mov AH, 02h[/SIZE]
[SIZE=2]mov DX, 0035h[/SIZE]
[SIZE=2]mov BH, 07h[/SIZE]
[SIZE=2]mov AH, 09h[/SIZE]
[SIZE=2]LEA DX, a[/SIZE]
[SIZE=2]int 10h[/SIZE]
[SIZE=2]mov AH,8[/SIZE]
[SIZE=2]int 21h[/SIZE]
[SIZE=2]mov AX,4c00h[/SIZE]
[SIZE=2]int 21h[/SIZE]
[SIZE=2]main endp[/SIZE]
[SIZE=2]codsg ends[/SIZE]
[SIZE=2]end main[/SIZE]
از كجا بفهمم كه كدوم خط برنامم اررور داره تو cmd؟
 
آخرین ویرایش:

the_king

مدیرکل انجمن
از كجا بفهمم كه كدوم خط برنامم اررور داره تو cmd؟

کامپایلر های اسمبلی اصولا سطری که خطا مربوط به آن است را مشخص می کنند، مثلا من از کامپایلر ML
مایکروسافت استفاده کردم و در دو سطر 6 و 13 وجود خطای نحوی را اعلام کرد :
کد:
C:\>ml c.asm
Microsoft (R) Macro Assembler Version 6.15.8803
Copyright (C) Microsoft Corp 1981-2000.  All rights reserved.

 Assembling: c.asm
c.asm([B]6[/B]) : error A2008: syntax error : c
c.asm([B]13[/B]) : error A2008: syntax error : :

C:\>

طبق اعلام ML شما مجاز به تعریف متغیری با نام c نیستید، چون جزو کلمات کلیدی کامپایلر است (مربوط به نوع
پارامتر های زبان c است) :
کد:
[B]c[/B] DB 'Monday','$'

همچنین در سطر 13 ام، بعد از assume از : استفاده کرده اید که اضافی است :
کد:
assume[B]:[/B] ss:stacksg, ds:datasg, cs:codsg

علاوه بر اون اشکالات نحوی، در نوشتن کد هم چند مورد ایراد دارد.
بایستی مقدار datasg را از طریق AX به DS منتقل می کردید، نه DX.
کد:
mov AX, datasg
mov [B]DX[/B], ax

دلیل نوشتن این بخش از کد را متوجه نشدم، اگر حذفشان می کردید اتفاق خاصی نمی افتاد :
کد:
mov AH, 06h
int 10h
mov AH, 02h
mov DX, 0035h
mov BH, 07h

سرویس چاپ یک رشته که به $ ختم شده در وقفه 21h است، نه 10h :
کد:
mov AH, 09h
LEA DX, a
int [B]10h
[/B]

کد زیر به درستی اجرا خواهد شد (نام متغیر ها را بصورت اختصاری sat و sun و mon و ... تغییر دادم) :
کد:
stacksg segment stack 'stack'
stacksg ends
datasg segment 'data'
    sat DB 'saturday','$'
    sun DB 'Sunday','$'
    mon DB 'Monday','$'
    tue DB 'Tuesday','$'
    wed DB 'Wednesday','$'
    thu DB 'Thursday','$'
    fri DB 'Friday','$'
datasg ends
codsg segment 'code'
assume ss:stacksg, ds:datasg, cs:codsg
main proc near 
    mov AX, datasg
    mov DS, ax
    mov AH, 09h
    LEA DX, sat
    int 21h
    mov AH,8
    int 21h
    mov AX,4c00h
    int 21h
main endp
codsg ends
end main

اگر از کامپایلر های مدرن استفاده کنید، کد ساده تر زیر معادل کد بالا است :
کد:
.MODEL  SMALL
.STACK
.DATA
    sat DB 'saturday','$'
    sun DB 'Sunday','$'
    mon DB 'Monday','$'
    tue DB 'Tuesday','$'
    wed DB 'Wednesday','$'
    thu DB 'Thursday','$'
    fri DB 'Friday','$'
.CODE
.STARTUP
    mov AH, 09h
    LEA DX, sat
    int 21h
    mov AH,8
    int 21h
.EXIT
END
 

hobab1987

Member
مجبورم با همين 3 تا فايل كار كنم (tasm.exe,tlink.exe,rtm) آخه كامپيوتري كه بايد برنامه ام را ارائه بدهم كامپايلر ندارد!!
با اين 3 تا فايل نميشود اشكال برنامه رو پيدا كرد!
راستي متغير ها و حلقه (تاريخ شمسي) را طبق توضيحي كه فرموديد نوشتم فقط آرايه اي كه گفتيد را بلد نيستم ،آرايه رو درس ندادند!
 

the_king

مدیرکل انجمن
مجبورم با همين 3 تا فايل كار كنم (tasm.exe,tlink.exe,rtm) آخه كامپيوتري كه بايد برنامه ام را ارائه بدهم كامپايلر ندارد!!
با اين 3 تا فايل نميشود اشكال برنامه رو پيدا كرد!
راستي متغير ها و حلقه (تاريخ شمسي) را طبق توضيحي كه فرموديد نوشتم فقط آرايه اي كه گفتيد را بلد نيستم ،آرايه رو درس ندادند!

تعریف کردن آرایه مورد خاص یا جدیدی نیست، مثلا کد زیر آرایه dmap را بصورت 14 بایتی تعریف می کند :
کد:
        dmap DB 0, 0, 0, 0, 0, 0, 0
             DB 0, 0, 0, 0, 0, 0, 0
می توان با اضافه کردن سطر های بیشتر یا اضافه کردن بایت ها در ادامه متن سطر ها، طول آرایه را تغییر داد.

برای خواندن مقدار اندیس های آرایه هم شیوه های مستقیم و غیر مستقیم وجود دارند.
مثلا کد زیر اولین اندیس آرایه dmap را از طریق اندیس SI در داخل AL می خواند :
کد:
        MOV SI, 0
        MOV AL, dmap[SI]

و کد زیر این عمل را بصورت مستقیم انجام می دهد :
کد:
        MOV AL, dmap[0]
 

hobab1987

Member
تاقسمتي برنامه را نوشتم اما ايراد دارد ( توصيه مي كنم اجرايش نكنيد!!!)
مقدار اوليه متغيير ها را مشخص كردم:
کد:
[SIZE=2]datasg segment 'data'[/SIZE]
[SIZE=2]day DB 00h[/SIZE]
[SIZE=2]pmonth DB 01h[/SIZE]
[SIZE=2]pday DB 01h[/SIZE]
[SIZE=2]datasg ends[/SIZE]
مقدار pmonth را چاپ كند و هروقت 1 واحد به ماه اضافه شد به اين كد برگردد و چاپ كند
کد:
[SIZE=2]MOV AH, 09h[/SIZE]
[SIZE=2]LEA DX, pmonth[/SIZE]
[SIZE=2]INT 21h[/SIZE]
pday هم همين طور , day تا 92 حركت دارد:
کد:
[SIZE=2]INC day[/SIZE]
[SIZE=2]MOV AH, 09[/SIZE]
[SIZE=2]LEA DX, pday[/SIZE]
[SIZE=2]INT 21h[/SIZE]
[SIZE=2]CMP day,31[/SIZE]
در پايان:
کد:
[SIZE=2]stacksg segment stack 'stack'[/SIZE]
[SIZE=2]stacksg ends[/SIZE]
[SIZE=2]datasg segment 'data'[/SIZE]
[SIZE=2]day DB 00h[/SIZE]
[SIZE=2]pmonth DB 01h[/SIZE]
[SIZE=2]pday DB 01h[/SIZE]
[SIZE=2]datasg ends[/SIZE]
[SIZE=2]codsg segment 'code'[/SIZE]
[SIZE=2]assume ss:stacksg, ds:datasg, cs:codsg[/SIZE]
[SIZE=2]main proc near [/SIZE]
[SIZE=2]MOV AX, datasg[/SIZE]
[SIZE=2]MOV Ds, ax[/SIZE]
[SIZE=2]loop1:[/SIZE]
[SIZE=2]MOV AH, 09h[/SIZE]
[SIZE=2]LEA DX, pmonth[/SIZE]
[SIZE=2]INT 21h [/SIZE]
[SIZE=2]loop2:[/SIZE]
[SIZE=2]INC day[/SIZE]
[SIZE=2]MOV AH, 09[/SIZE]
[SIZE=2]LEA DX, pday[/SIZE]
[SIZE=2]INT 21h[/SIZE]
[SIZE=2]CMP day,31[/SIZE]
[SIZE=2]JNE loop2[/SIZE]
[SIZE=2]INC pmonth[/SIZE]
[SIZE=2]MOV pday, 01[/SIZE]
[SIZE=2]CMP day,92[/SIZE]
[SIZE=2]JNE loop2[/SIZE]
[SIZE=2]MOV AH,8[/SIZE]
[SIZE=2]INT 21h[/SIZE]
[SIZE=2]MOV AX,4c00h[/SIZE]
[SIZE=2]INT 21h[/SIZE]
[SIZE=2]main endp[/SIZE]
[SIZE=2]codsg ends[/SIZE]
[SIZE=2]end main[/SIZE]
 

the_king

مدیرکل انجمن
این چند مورد را در نظر بگیرید :

1) سرویس 9 از وقفه 21h برای چاپ یک رشته ای بکار رود که به کاراکتر $ ختم شده باشد، پس برای چاپ
یک متغیر عددی تک بایتی مانند pmount مناسب نیست :
کد:
MOV AH, 09h
LEA DX, pmonth
INT 21h

شما بایستی عدد موجود در pmount را به یک رشته تبدیل کرده و سپس آنرا چاپ کنید. کد زیر برای چاپ یک
عدد دو رقمی مناسب است :
کد:
    MOV     AL, pmonth
    MOV     AH, 0
    MOV     DL, 10
    DIV     DL
    ADD     AX, 3030h
    PUSH    AX
    MOV     DL, AL
    MOV     AH, 2
    INT     21H
    POP     DX
    MOV     DL, DH
    INT     21H

برای آنکه کدتان کوتاه تر شود، می توانید این روتین را به یک صورت یک زیر روال با CALL فراخوانی کنید :
کد:
    MOV     AL, pmonth
    CALL    [B]print_al[/B]
.
.
.
.
[B]print_al:[/B]
    MOV     AH, 0
    MOV     DL, 10
    DIV     DL
    ADD     AX, 3030h
    PUSH    AX
    MOV     DL, AL
    MOV     AH, 2
    INT     21H
    POP     DX
    MOV     DL, DH
    INT     21H
    RET
دقت کنید که خود روتین print_al در مسیر عادی اجرای برنامه نباشد، مثلا بهتر است بعد از کد خروج از برنامه
قرار گیرد، چون بایستی صرفا توسط CALL فراخوانی شود.

اکنون با استفاده از این روال می توانید سایر متغیر ها را هم به سادگی نمایش دهید :
کد:
    MOV     AL, pday
    CALL    [B]print_al[/B]

2) شما بایستی مقدار pday را بعد از چاپ مقدارش افزایش دهید که آنرا فراموش کرده اید.

3) برای مقایسه مقدار روز با 31 بایستی بجای day از pday استفاده کنید، زیرا day مجموع کل روز های سپری
شده از فصل است و در دو ماه اردیبهشت و خرداد همواره مقدارش مخالف 31 است.
در ضمن چون pday از 1 شروع می شود، بجای 31 بایستی با 32 مقایسه اش کنید.
کد:
CMP [B]day[/B],31
JNE loop2

4) شما در انتهای حلقه مقدار day را 92 مقایسه کرده اید، در حالی که 92 خود جزو اعدادی است که بایستی
مورد قبول قرار گیرد. بایستی day را با 93 مقایسه کنید.
کد:
CMP day,[B]92[/B]

5) اگر قصد دارید که مقدار ماه برای اردیبهشت و خرداد نمایش داده شوند، بایستی به حلقه loop1 برگردید، نه loop2 :
کد:
CMP day,92
JNE [B]loop2[/B]
 

hobab1987

Member
از توضيح خوبتون سپاسگذارم!!!
چند تا سوال پيش اومد!
== === == ==
شما بایستی عدد موجود در pmount را به یک رشته تبدیل کرده و سپس آنرا چاپ کنید. کد زیر برای چاپ یک
عدد دو رقمی مناسب است :
کد:
MOV AL, pmonth
MOV AH, 0
MOV DL, 10
DIV DL
ADD AX, 3030h
PUSH AX
MOV DL, AL
MOV AH, 2
INT 21H
POP DX
MOV DL, DH
INT 21H
تبديل عدد به رشته را ميشود توضيح دهيد؟!
کد:
MOV AL, pday
CALL print_al
pmonth رو قبلا در ALگذاشتيد حالا دوباره در AL يك متغيير ديگر گذاشتيد اين مقدار ها اشتباه نميشود؟


دوباره از اول برنامه رو نوشتم.
و كد تبديل رشته هم قرار دادم بعد از اين: 1 ERROR
کد:
[SIZE=2]main proc far [/SIZE]
[SIZE=2]MOV AX, datasg[/SIZE]
[SIZE=2]MOV DS, AX[/SIZE]
[SIZE=2]MOV AL, pday[/SIZE]
[SIZE=2]loop_pday:[/SIZE]
[SIZE=2]CALL print-pday[/SIZE]
[SIZE=2]INC AL[/SIZE]
[SIZE=2]INC day[/SIZE]
[SIZE=2]CMP AL, 32[/SIZE]
[SIZE=2]JNE loop_pday[/SIZE]
[SIZE=2]DEC day[/SIZE]
[SIZE=2]INC pmonth[/SIZE]
[SIZE=2]CMP day, 93[/SIZE]
[SIZE=2]JE loop_quit[/SIZE]
[SIZE=2]MOV AL, 01h[/SIZE]
[SIZE=2]JMP loop_pday[/SIZE]
[SIZE=2]MOV AH, 08h[/SIZE]
[SIZE=2]INT 21H[/SIZE]
[SIZE=2]loop_quit:[/SIZE]
[SIZE=2]MOV AX, 4c00h[/SIZE]
[SIZE=2]INT 21H [/SIZE]
[SIZE=2]main endp[/SIZE]
[SIZE=2]print_pday proc near[/SIZE]
[SIZE=2].[/SIZE]
[SIZE=2].[/SIZE]
[SIZE=2].[/SIZE]
 

the_king

مدیرکل انجمن
از توضيح خوبتون سپاسگذارم!!!
چند تا سوال پيش اومد!
== === == ==
تبديل عدد به رشته را ميشود توضيح دهيد؟!

شما یک بایت را بصورت عددی می خواهید چاپ کنید، مثلا pmount DB 12 را در نظر بگیریم. برای چاپ عدد 12
بر روی صفحه نمایش بایستی دو کاراکتر "1" و "2" را به ترتیب چاپ کنیم. ابتدا عدد 12 را بر 10 تقسیم خواهیم کرد
و سپس کاراکتر "0" را به دو رقم 1 (حاصل تقسیم بدون اعشار) و 2 (باقیمانده تقسیم) اضافه می کنیم تا
اعداد بصورت کاراکتر های "1" و "2" در آیند :
کد:
1 + "0" = "1"
2 + "0" = "2"

pmonth رو قبلا در ALگذاشتيد حالا دوباره در AL يك متغيير ديگر گذاشتيد اين مقدار ها اشتباه نميشود؟

نام print_al هیچ ارتباطی با نام متغیری که قصد چاپش را دارید ندارد، دلیلی نداشت که اسم آنرا به print_pday
تغییر می دادید. قرار است این روتین برای چاپ مقادیر ماه و روز میلادی و قمری هم بکار رود، پس بهتر است
از اسمی که دقیقا کار آن را نشان دهد استفاده کنید، این روتین مقدار فعلی AL را چاپ می کند، به همین جهت نام
آنرا print_al گذاشتم.

ما پیش از فراخوانی CALL مقدار AL را تعیین می کنیم، منظورتون از اشتباه شدن مقدار ها را متوجه نشدم.

در نوشتن کدتان چند اشکال وجود دارد :

1) شما با CALL print-pday روتین print-pday را فراخوانی می کنید در حالی که نام روتین را print_pday قرار داده اید،
بدیهی است که کاراکتر _ با - فرق می کند.

2) قرار نبود که روتین print_al را بیرون از پروسه Main قرار دهید، توصیه می کنم که آنرا به همان شیوه سابق قبل
از main endp و بعد از کد خروج از برنامه بصورت : print_al بنویسید، نه Proc
 

hobab1987

Member
Sorry

mov ah, 0
mov dl, 10
div dl
add ax, 3030h
push ax
mov dl, al
mov ah, 2
int 21h
pop dx
mov dl, dh
int 21h
كلا نفهميدم چرا اين اينجوري نوشته شده!!:)
مخصوصا جمع 3030
مواردي كه در پست قبل گفتيد انجام دادم اما error دارد !!!
 
آخرین ویرایش:

the_king

مدیرکل انجمن
كلا نفهميدم چرا اين اينجوري نوشته شده!!:)
مخصوصا جمع 3030

دستور div یک بایتی (یعنی اگر پارامتر فرمان div را یک بایت مثلا dl یا bl یا ch باشد) همواره مقدار AX را بر آن
پارامتر تقسیم می کند، AX هم از دو بخش AL و AH تشکیل شده، AL که عدد مورد نظر ماست، پس بایستی
مقدار AH را پیش از تقسیم صفر کنیم :
کد:
mov ah, 0

ما می خواهیم عدد مان را بر 10 تقسیم کنیم تا دو رقم یکان و دهگان جدا شوند، برای تقسیم از DL استفاده کردیم :
کد:
mov dl, 10

و تقسیم را بر DL ( بر 10) انجام می دهیم :
کد:
div dl

حاصل تقسیم AL و باقیمانده AH است، ما هر دو را یکجا (AX) را با کاراکتر "0" با کد اسکی 48 (30 مبنای 16)
جمع می کنیم تا اعداد به کاراکتر معادلشان تبدیل شوند :
کد:
add ax, 3030h

کد بالا را می توان به این شکل هم نوشت :
کد:
add al, 30h
add ah, 30h

ما پیش از چاپ مقدار AL، بایستی مقدار AH را جای دیگری حفظ کنیم، چرا؟ چون برای استفاده از سرویس 02h
وقفه 21h که چاپ کاراکتر را انجام می دهد، بایستی مقدار AH را روی 02h تنظیم کنیم، پس مقدار قبلی AH
از دست می رود، برای حفظ مقدار AH هم چه جایی بهتر از پشته، چون پشته 16 بیتی است، دستور PUSH AH
قابل قبول نیست، پس بجایش AX را در پشته قرار می دهیم :
کد:
push ax

برای چاپ یک کاراکتر با سرویس 02h ، بایستی کاراکتر در DL قرار گیرد :
کد:
mov dl, al

کد سرویس (02h) هم بایستی در AH قرار گیرد :
کد:
mov ah, 2

و وقفه برای نمایش کاراکتر AL (رقم دهگان) اجرا شود :
کد:
int 21h

پس از چاپ کاراکتر اول، نوبت چاپ کاراکتر دوم است، پس ابتدا کاراکتر موجود در AH را مجددا از پشته بر می گردانیم،
البته در DX :
کد:
pop dx

کاراکتر را از DH به DL انتقال می دهیم، چون سرویس 02h کاراکتر موجود در DL را چاپ می کند :
کد:
mov dl, dh

و کاراکتر دوم (یکان) چاپ می شود :
کد:
int 21h

مواردي كه در پست قبل گفتيد انجام دادم اما error دارد !!!

من همینطوری تو هوا که نمی تونم بگم کجای کد Error می دهد.
 

hobab1987

Member
مرســــي دوستم !!!:rose:
بفرما اين هم كد:

کد:
stacksg segment stack 'stack'
stacksg ends
datasg segment 'data'
day DB 00H
pmonth DB 01H
pday DB 01H
msg1 DB 'Farvardin: ','$'
msg2 DB 'Ordibehesht: ','$'
msg3 DB 'Khordad: ','$'
datasg ends
codsg segment 'code'
assume ss:stacksg, ds:datasg, cs:codsg
main proc far 
MOV AX, datasg
MOV DS, AX
MOV AL, pday
loop_pday:
CALL print_al
INC AL
INC day
CMP AL, 32
JNE loop_pday
DEC day
INC pmonth
CMP day, 93
JE loop_quit
MOV AL, 01h
JMP loop_pday
MOV AH, 08h
INT 21H
loop_quit:
MOV AX, 4c00h
INT 21H 
print_al:
MOV AH, 0
MOV DL, 10
DIV DL
ADD AX, 3030h
PUSH AX
MOV DL, AL
MOV AH, 2
INT 21H
POP DX
MOV DL, DH
INT 21H
RET
main endp
codsg ends
end main
 

the_king

مدیرکل انجمن
1) تنها زمانی از far استفاده کنید که کدتان آنقدر بزرگ شده که در 64 کیلوبایت جا نمی شود، در برنامه های
کوچک far کاربردی که ندارد هیچ، شما را درگیر اضافه کردن near برای ارجاع های درون کدی هم می کند :
کد:
main proc [B]far[/B]

2) مگر نمی خواهید مقدار pday را در داخل حلقه چاپ کنید؟ پس چرا مقدارش را بجای درون حلقه،
پیش از حلقه در AL قرار می دهید؟ این عمل باید درون حلقه انجام گیرد، نه بیرون از آن. مخصوصا که در درون
حلقه ممکن است هزار بلا سر مقدار AL بیاید، مثلا در هنگام چاپ با print_al مقدار AL تغییر می کند.
کد:
MOV AL, pday
loop_pday:

3) این کد هم مثل مورد قبلی نادرست است، بایستی مقدار pday را افزایش دهید، نه AL :
کد:
INC AL

4) و بجای مقایسه AL مقدار pday را مقایسه کنید :
کد:
CMP AL, 32

5) این کاهش مقدار day چه مفهومی دارد؟ یک ماه قرار است 31 روزه باشد، شما با کاهش مقدار روز های
سپری شده به ازای هر ماه یکبار ، عملا کنترل اجرای حلقه را از بین می برید.
چون از برنامه می خواهید که چند ماه 31 روزه را سپری کند ولی هر ماه را 30 روز حساب کند، بعد زمانی که مجموع
روزهای سپری شده به 93 رسید کارش را خاتمه دهد، خوب بدیهی است که 93 به 30 قابل قسمت نیست و برنامه
به این راحتی کارش را خاتمه نمی دهد.
کد:
DEC day

6) این کد هم پیرو آن اشتباه قبلی است، بایستی مقدار pday را به 1 تغییر دهید، نه AL را :
کد:
MOV AL, 01h

کد زیر قابل اجرا است، در ضمن بین نمایش هر روز، یک کاراکتر فاصله (کد 32) را چاپ کردم تا اعداد به هم
نچسبند :

کد:
stacksg segment stack 'stack'
stacksg ends
datasg segment 'data'
	day	DB 00H
	pmonth	DB 01H
	pday	DB 01H
	msg1	DB 'Farvardin: ','$'
	msg2	DB 'Ordibehesht: ','$'
	msg3	DB 'Khordad: ','$'
datasg ends
codsg segment 'code'
assume ss:stacksg, ds:datasg, cs:codsg
main proc
	MOV	AX, datasg
	MOV	DS, AX
	loop_pday:
	MOV	AL, pday
	CALL print_al
	MOV	ah, 2
	MOV	dl, 32
	int	21h
	INC	pday
	INC	day
	CMP	pday, 32
	JNE	loop_pday
	CMP	day, 93
	JE	loop_quit
	INC	pmonth
	MOV	pday, 1
	JMP	loop_pday
	MOV	AH, 08h
	INT	21H
	loop_quit:
	MOV	AX, 4c00h
	INT	21H 
	print_al:
	MOV	AH, 0
	MOV	DL, 10
	DIV	DL
	ADD	AX, 3030h
	PUSH	AX
	MOV	DL, AL
	MOV	AH, 2
	INT	21H
	POP	DX
	MOV	DL, DH
	INT	21H
	RET
main endp
codsg ends
end main
 

hobab1987

Member
پس چرا براي من اجرا نمي شود؟!






اجــــــــــــــــــــــــــرا شد!!!:oops:
من اينجا متوجه يك چيزي شدم:
وقتي برنامه اي را كه ERROR دارد اجرا مي كنم اين در ذهنش مي‌ماند و از يادش نمي‌رود!!!:-?
حتي اگر ERROR بر طرف شده باشد!!!


حالا كد رنگ رو بنويسيم يا تقويم قمري و ميلادي را؟!
كد ها زياد شده از كجا شروع كنيم؟!
 
آخرین ویرایش:

the_king

مدیرکل انجمن
حالا كد رنگ رو بنويسيم يا تقويم قمري و ميلادي را؟!
كد ها زياد شده از كجا شروع كنيم؟!
به خودتان بستگی دارد، چه بخواهید روزهای تعطیل را رنگی کنید، و چه بخواهید تقویم قمری یا میلادی را
نمایش دهید، در هر صورت اول بایستی جدول dmap را بسازید و پر کنید. البته مطابق با سلیقه تان.
چون اگر روز تعطیلی در تقویم نبود که آخر ماه های قمری یا میلادی باشد یا آخر ماه های قمری و میلادی در
یک روز واحد قرار نگیرند ، که احتمالا چنین است، کدتان می تواند ساده تر شود. مثلا :
0 برای روز عادی
1 برای روز تعطیل
2 برای پایان ماه قمری
3 برای پایان ماه میلادی
 

hobab1987

Member
من نمي دونم چه طوري از اين dmap استفاده كنم!
چه دستوري بايد بدهم؟
يعني وقتي روز تعطيل pday ام شد بگم 1 بشه و رنگ اش بكند؟!
متوجه نشدم!!

براي ماه قمري و ميلادي همان كد را در ادامه كپي كردم البته با تغيير متغيير ها و مقدارشان اما اجرا نشد! كار اشتباهي كردم؟!
 

the_king

مدیرکل انجمن
من نمي دونم چه طوري از اين dmap استفاده كنم!
چه دستوري بايد بدهم؟
يعني وقتي روز تعطيل pday ام شد بگم 1 بشه و رنگ اش بكند؟!
متوجه نشدم!!
مقدار day را در BX یا SI یا DI کپی می کنید و سپس مقدار [dmap[BX یا [dmap[SI را با 1 مقایسه کنید، که اگر
1 بود رنگ را عوض کنید :
کد:
MOV	BX, day
CMP	dmap[BX], 1
JE	labelname

براي ماه قمري و ميلادي همان كد را در ادامه كپي كردم البته با تغيير متغيير ها و مقدارشان اما اجرا نشد! كار اشتباهي كردم؟!
کد قمری و میلادی اندکی متفاوت است، در آن بخشی که مقدار روز شان را با آخرین روز ماه مقایسه می کنید،
دیگر مقدار ثابت 31 وجود ندارد، چون یک ماه ممکن است 30 روزه باشد و یک ماهی 31 روزه.
بایستی بررسی کنید که آیا [dmap[BX برابر 2 یا 3 هست یا خیر. و اگر بود مقدار روز میلادی یا قمری را 1 نموده و
مقدار ماه را افزایش دهید.
 

hobab1987

Member
کد:
mov    bx, day
cmp    dmap[bx], 1
je    labelname
خوب اين مقايسته اي كه صورت مي گيرد :
مثلا بيان مي كند كه :فلان روز 1 هست يا خير ، گفتيد 1 نماينده ي روز هاي تعطيل است خوب چه طوري 1 ميتونه نماينده روز تعطيل باشد يا 2 يا 3 نماينده روز خاص ديگر!!!
 

the_king

مدیرکل انجمن
کد:
mov    bx, day
cmp    dmap[bx], 1
je    labelname
خوب اين مقايسته اي كه صورت مي گيرد :
مثلا بيان مي كند كه :فلان روز 1 هست يا خير ، گفتيد 1 نماينده ي روز هاي تعطيل است خوب چه طوري 1 ميتونه نماينده روز تعطيل باشد يا 2 يا 3 نماينده روز خاص ديگر!!!

مثلا فرض کنیم که در dmap به ترتیب اعداد 1 و 0 و 0 و 0 و 2 و 0 و 0 و 1 و 0 و 3 ذخیره بشه.
مقدار اولیه day هم که صفر باشد.

مقدار dmap برای روز اول (day = 0) برابر 1 است (dmap[0] = 1) پس روز اول تعطیل است.
مقدار dmap برای روز دوم (day = 1) برابر 0 است (dmap[1] = 0) پس روز دوم یک روز عادی است.
مقدار dmap برای روز سوم (day = 2) برابر 0 است (dmap[2] = 0) پس روز سوم یک روز عادی است.
مقدار dmap برای روز چهارم (day = 3) برابر 0 است (dmap[3] = 0) پس روز چهارم یک روز عادی است.
مقدار dmap برای روز پنجم (day = 4) برابر 2 است (dmap[4] = 2) پس روز پنجم آخرین روز ماه قمری است.
مقدار dmap برای روز ششم (day = 5) برابر 0 است (dmap[5] = 0) پس روز ششم یک روز عادی است.
مقدار dmap برای روز هفتم (day = 6) برابر 0 است (dmap[6] = 0) پس روز هفتم یک روز عادی است.
مقدار dmap برای روز هشتم (day = 7) برابر 1 است (dmap[7] = 1) پس روز هشتم تعطیل است.
مقدار dmap برای روز نهم (day = 8) برابر 0 است (dmap[8] = 0) پس روز نهم یک روز عادی است.
مقدار dmap برای روز دهم (day = 9) برابر 3 است (dmap[9] = 3) پس روز دهم آخرین روز ماه میلادی است.

و به همین ترتیب برای سایر روز ها...
 

جدیدترین ارسال ها

بالا