کامپیوتر مرد کوچک

کامپیوتر مرد کوچک یک مدل سفارشی از کامپیوتر است، که توسط دکتر استوارت مادنیک در سال ۱۹۶۵ میلادی ساخته شد. این کامپیوتر در حالت کلی برای آموزش دانشجویان مورد استفاده قرار می‌گیرد، زیرا یک کامپیوتر با معماری ون نیومن ساده – که شامل تمامی ویژگی‌های اساسی کامپیوترهای مدرن است - را مدل می‌کند. این نوع کامپیوتر قابلیت برنامه‌ریزی شدن در زبان ماشین (دهدهی به جای دودویی) یا زبان اسمبلی را دارد.
این مدل بر اساس مفهوم حبس کردن یک مرد کوچک در یک اتاق پستی دربسته تعریف شده‌است (مشابه با یک کامپیوتر در این طرح). در یک سوی انتهایی اتاق ۱۰۰ جعبه نامه (حافظه) وجود دارد که از ۰ تا ۹۹ شماره‌گذاری شده‌اند، که هر کدام می‌تواند شامل یک دستورالعمل یا داده ۳ رقمی باشد (از رنج ۰۰۰ تا ۹۹۹). به‌علاوه دو جعبه نامه در سمت دیگر انتهایی اتاق قرار دارد که با برچسب‌های INBOX و OUTBOX برچسب‌گذاری شده‌اند و برای ارسال و دریافت داده‌ها استفاده می‌شوند. در مرکز اتاق یک محوطه کاری وجود دارد که شامل ۱) دو دستورالعمل ساده محاسباتی است (جمع و تفریق) که آن را به نام انباره و ۲) یک شمارش‌گر قابل بازنشاندن که با نام «شمارش‌گر برنامه» می‌شناسیم. این شمارش‌گر برنامه آدرس دستورالعمل بعدی که مرد کوچک آن را انجام خواهد داد، نگاه می‌دارد. افزایش یک واحدی شمارشگر برنامه در حالت عادی بعد از اجرای هر دستورالعمل، به مرد کوچک اجازه می‌دهد تا در طی یک برنامه بطور متوالی فعالیت داشته باشد. دستورالعمل‌های انشعاب اجازه قراردادن تکرار (حلقه) و ساختارهای برنامه ایی شرطی را در یک برنامه می‌دهند. قرار دادن شمارشگر برنامه بر روی یک آدرس غیر متوالی در صورت رخداد یک شرط خاص (نوعا در اینجا وقتی مقدار داخل انباره صفر یا مثبت شود).
هر جعبه نامه (نشان دهنده یک مکان حافظه منحصر به فرد) شامل هردوی دستورالعمل‌ها و داده هاست. در نتیجه بایستی مراقب بود تا زمانی‌که یک آدرس حافظه شامل داده است، شمارشگر برنامه را از افزایش بازداریم (مرد کوچک تلاش می‌کند تا آن را برای یک دستورالعمل متوقف نکند). این مزیت نی تواند با نوشتن دستورالعمل‌ها در جعبه نامه بدست آید که به معنی آن است که کد مورد وقفه قرار گرفته تا یک کد خوداصلاحگر ایجاد نماید. برای استفاده از کامپیوتر مرد کوچک، کاربر داده‌ها را در جعبه‌های نامه بارگذاری می‌نماید و سپس برای شروع اجرا به مرد کوچک اطلاع می‌دهد؛ که با دستورالعمل ذخیره شده در خانه صفر حافظه آغاز می‌شود. در یک حالت متفاوت، ریست کردن شمارشگر برنامه به صفر، باعث راه اندازی مجدد برنامه می‌شود.
چرخه اجرا
مرد کوچک برای اجرای یک برنامه مراحل زیر را اعمال می‌کند:
شمارشگر برنامه را برای شماره صندوق پستی که شامل دستورالعمل برنامه است، چک می‌کند.
دستورالعمل را بوسیله این شماره واکشی می‌کند. هر دستورالعمل شامل ۲ فیلد است: یک آپکد opcode (نشان دهنده عملیات اعمالی) و یک فیلد آدرس (نشان دهنده مکان داده ایست که روی آن عملیات اعمال می‌شود).
افزایش شمارشگر برنامه (که شامل شماره صندوق پستی از دستورالعمل بعدی است).
دیکد کردن دستورالعمل. اگر دستورالعمل از داده‌های ذخیره شده در صندوق پستی دیگری استفاده کند سپس از فیلد آدرس برای پیدا کردن شماره صندوق پستی استفاده می‌کند تا این داده‌ها بدست آورد (به عنوان مثال، دریافت اطلاعات از صندوق پستی ۴۲).
واکشی داده‌ها (از ورودی، انباره، یا صندوق پستی با آدرس تعیین شده در مرحله 4).
اجرای عملیات بر پایه آپکد داده شده.
انشعاب یا ذخیره نتیجه (در خروجی، انباره، یا صندوق پستی با آدرس تعیین شده در مرحله ۴).
بازگشت به شمارشگر برنامه برای تکرار حلقه یا پایان داده با آن.
دستورات
در حالی که کامپیوتر مرد کوچک منعکس‌کننده عملکرد واقعی پردازنده دودویی می‌باشد، سادگی اعداد اعشاری انتخاب شده برای به حداقل رساندن پیچیدگی برای دانش آموزانی که ممکن است در کار با دودویی/هگزادسیمال مشکل داشته باشند.
دستورالعمل‌ها
برخی از شبیه‌سازهای این نوع کامپیوتر به‌طور مستقیم با استفاده از ۳ دستورالعمل عددی و برخی دیگر با استفاده از ۳-کد حفظی نامه و برچسب، برنامه‌ریزی شده‌اند. در هر صورت این مجموعه دستورالعمل به‌طور عامدانه برای ساده کردن درک، بسیار محدود است (به‌طور معمول حدود ده دستورالعمل). اگر این کامپیوتر از کد حفظی و برچسب استفاده کند سپس هنگامی که برنامه اسمبل شده است، اینها به ۳ دستورالعمل عددی تبدیل می‌شوند.
جدول زیر یک نمونه مجموعه دستورالعمل عددی و کدهای حفظی معادل آن را نشان می‌دهد.
+ Instructions
کد عددی
کد حفظی
دستورالعمل
توضیحات
1xx
ADD
ADD
مقدار ذخیره شده در صندوق پستی xx را به مقدار موجود در انباره اضافه می‌کند (حسابگر).
نکته: محتوای صندوق پستی تغییر نمی‌کند، و عمل‌های انباره (حاسبگر) برای دستورالعمل‌های جمعی که جمع‌های بیشتر از ۳ را انجام می‌دهند، تعریف نشده‌اند. بطور مشابه برای تفریق، می‌توان یک پرچم منفی بر روی سرریز درنظر گرفت.
2xx
SUB
SUBTRACT
مقدار ذخیره شده در صندوق پستی xx را از مقدار موجود در انباره تفریق می‌کند (حسابگر).
نکته: محتوای صندوق پستی تغییر نمی‌کند، و عمل‌های انباره (حاسبگر) برای دستورالعمل‌های تفریق که نتایج منفی می‌دهند، تعریف نشده‌اند-اگر چه یک پرچم منفی نشانده خواهد شد تا در نتیجه (7xx (BRZ و (8xx (BRP بتوانند به درستی استفاده شوند.
3xx
STA
STORE
ذخیره مقادیر موجود در انباره در صندوق پستی xx (ویرانگر).
نکته: مقادیر انباره (حسابگر) بدون تغییر باقی می‌مانند (تخریب نمی‌شوند)، اما مقادیر صندوق پستی یا مقداری که در آنجا بوده جایگزین می‌شوند (تخریب می‌شوند).
5xx
LDA
LOAD
مقدار صندوق پستی xx را بارگذاری می‌کند (از بین نمی‌برد) و آن را به انباره وارد می‌کند (از بین می‌برد).
6xx
BRA
BRANCH (غیرشرطی)
شمارشگر برنامه را به آدرس داده شده تنظیم می‌کند (مقدار xx). یعنی مقدار xx دستورالعمل بعدی خواهد بود که اجرا می‌شود.
7xx
BRZ
BRANCH IF ZERO (شرطی)
اگر انباشتگر (حسابگر) محتوی مقدار ۰۰۰ بود، شمارشگر برنامه را برابر مقدار xx قرار بده. در غیر این صورت هیچ عملی انجام نده. اگر چه پرچم منفی به حساب آورده شده تعریف نشده باشد. زمانی‌که تفریق باعث پاریز انباشتگر می‌شود، این پرچم تنظیم می‌شود، بعد از اینکه انباشتگر تعریف نشده باشد، به صورت بالقوه صفر، باعث تعریف نشده بودن رفتار BRZ روی پاریز می‌باشد. رفتار پیشنهادی اگر انباشتگر مقدار صفر و پرچم منفی نیز تنظیم نشده باشد، انشعاب می‌شود.
نکته: تا زمانی که برنامه در حافظه ذخیره ذخیره می‌شود، تمامی داده‌ها و دستورالعمل‌های برنامه فرمت آدرس/مکان یکسانی دارند.
8xx
BRP
BRANCH IF POSITIVE (شرطی)
اگر انباره صفر یا مثبت باشد، شمارشگر برنامه بر روی xx تنظیم می‌شود. در غیر اینصورت هیچ عملی انجام نمی‌دهد. از آنجایی که سلول‌های حافظه در این نوع کامپیوترها تنها مقادیر بین ۰ تا ۹۹۹ را می‌پذیرند، این دستورالعمل تنها به پرچم منفی که با یک پاریز روی تفریق و بطور بالقوه روی یک سریز جمع تنظیم می‌شوند، وابسته است (تعریف نشده).
نکته: تا زمانی که برنامه در حافظه ذخیره ذخیره می‌شود، تمامی داده‌ها و دستورالعمل‌های برنامه فرمت آدرس/مکان یکسانی دارند.
۹۰۱
INP
INPUT
برو به صندوق ورودی، مقدار را از کاربر واکشی کن، و در انباره (حسابگر) قرار ده
نکته: این عمل باعث بازنویسی هر مقداری که داخل انباره بوده‌است می‌شود (مخرب).
۹۰۲
OUT
OUTPUT
مقدار را از انباره به صندوق خروجی کپی کن.
اعلان: محتوای انباره تغییر نمی‌کند (غیر مخرب).
۰۰۰
HLT/COB
HALT/COFFEE BREAK
کار را متوقف کن/ برنامه را پایان ده
DAT
DATA
این یک دستور اسمبلی است که به سادگی مقدار را درون صندوق پستی دردسترس بعدی بار می‌کند.
DAT همچنین می‌تواند در تلفیق با برچسب‌ها برای تعریف متغیرها استفاده شود. برای مثال DAT 984 مقدار ۹۸۴ درون صندوق پستی در آدرسی که در دستور DAT قرار دارد، ذخیره می‌کند.
نمونه‌ها
استفاده از کدهای دستورالعملی عددی
این برنامه (دستورالعمل ۹۰۱ به دستورالعمل ۰۰۰ ) فقط با استفاده از کدهای عددی نوشته شده‌است. این برنامه دو عدد را به عنوان ورودی و خروجی متفاوت می‌گیرد. توجه کنید که اجرا در صندوق پستی ۰۰ شروع می‌شود و پس از آن در صندوق پستی ۰۷ اتمام می‌یابد. معایب برنامه‌نویسی کامپیوتر مرد کوچک، استفاده از کدهای دستورالعملی عددی مورد بحث در زیر است.
صندوق پستی
کد عددی
عملیات
نظرات
۰۰
۹۰۱
صندوق ورودی--> انباره
ورودی اولین شماره وارد کردن در حسابگر (پاک کردن هر آنچه وجود دارد)
۰۱
۳۰۸
انباره--> حافظه۰۸
ذخیره مقدار فعلی حسابگر (آماده شدن برای مرحله بعدی…)
۰۲
۹۰۱
صندوق ورودی --> انباره
ورودی دومین شماره وارد کردن در حسابگر (پاک کردن هر آنچه وجود دارد)
۰۳
۳۰۹
انباره--> حافظه۰۹
ذخیره مقدار فعلی حسابگر (دوباره آماده شدن برای مرحله بعدی…)
۰۴
۵۰۸
حافظه۰۸ --> انباره
(اکنون هر دو مقادیر ورودی ذخیره شده در صندوق پستی ۰۸ و ۰۹… هستند)
بارگیری مقدار اول به حسابگر (پاک کردن هر آنچه وجود دارد)
۰۵
۲۰۹
انباره= انباره- حافظه۰۹
تفریق عدد دوم از مقدار فعلی حسابگر (که فقط تنظیم می‌شود به شماره اول)
۰۶
۹۰۲
انباره--> صندوق خروجی
خروجی نتیجه حسابگر به صندوق خروجی
۰۷
۰۰۰
(بدون عملیات انجام شده)
توقف کامپیوتر
استفاده از حفظیات و برچسب‌ها
زبان اسمبلی یک زبان برنامه‌نویسی سطح پایین است که به جای کدهای دستورالعمل عددی از حفظیات و برچسب‌ها استفاده می‌کند. اگرچه کامپیوترهای مرد کوچک تنها از یک دسته محدود از حفظیات استفاده می‌کنند، راحتی استفاده از یک حفظی برای هر دستورالعمل از زبان اسمبلی همان برنامه-که در زیر نشان داده شده-روشن می‌سازد. برنامه‌نویس نیازی به بخاطر سپردن یک مجموعه از کدهای عددی بینام ندارد و اکنون می‌تواند بوسیله یک مجموعه از کدهای بیشتر حفظی قابل یادآوری برنامه‌ریزی شود. اگر این حفظی یک دستورالعمل شامل یک آدرس حافظه باشد (یک دستور انشعاب یا بارگیری/ذخیره داده) سپس یک برچسب برای نامگذاری آدرس حافظه استفاده می‌شود.
این مثال برنامه‌ای است که می‌تواند روی یک شبیه‌ساز کامپیوتر مرد کوچک کامپایل و اجرا می‌شود قابل دسترس در وب سایت دانشگاه یورک (تورنتو، کانادا) یا روی یک برنامه کاربردی که توسط Mike Coley نوشته شده‌است. تمام این شبیه‌سازها شامل تمامی دستورالعمل‌ها و برنامه‌های ساده، یک اسمبلر برای تبدیل کد اسمبلی به کد ماشین، و یک توضیح جزئیاتی مرحله به مرحله از هر دستورالعمل کامپیوتر مرد کوچک است.
INP
STA FIRST
INP
STA SECOND
LDA FIRST
SUB SECOND
OUT
HLT
FIRST DAT
SECOND DAT
برچسب‌ها
بدون برچسب‌ها برنامه‌نویس نیازمند به محاسبه دستی آدرس‌های صندوق پستی (حافظه) است. در مثال کد عددی، اگر یک دستورالعمل جدید قبل از دستورالعمل HLT پایانی، وارد شود، سپس این دستورالعمل HLT از آدرس ۰۷ به ۰۸ انتقال می‌یابد (برچسب‌گذاری آدرس از مکان ۰۰ شروع می‌شود). فرض کنید کاربر ۶۰۰ را به عنوان اولین ورودی وارد کند. دستورالعمل ۳۰۸ معنی می‌دهد که این مقدار در آدر ۰۸ ذخیره خواهد شد و دستورالعمل 000 (HLT) بازنویسی می‌شود؛ بنابراین ۶۰۰ معنی می‌دهد "انشعاب به صندوق پستی آدرس ۰۰" برنامه به جای توقف، در یک چرخه بی‌پایان قرار خواهد گرفت.
برای کار روی این مشکل، اکثر زبان‌های اسمبلی (شامل کامپیوتر مرد کوچک) شامل محفوظات و برچسبهاست. یک برچسب به‌طور ساده یک کلمه است که برای نام یک آدرس حافظه که یک دستورالعمل یا داده ذخیره شده‌اند، یا ارجاع به آدرس داخل دستورالعمل.
زمانیکه یک برنامه اسمبل می‌شود:
یک برچسب در قسمت چپ از یک دستورالعمل حفظی به یک آدرس حافظه‌ای که دستورالعمل یا داده در آن ذخیره شده تبدیل می‌شود. مانند loopstart INP
یک برچسب در قسمت راست از یک دستورالعمل حفظی مقدار آدرس حافظه‌ای را که به بالا اشاره می‌کند را بدست می‌دهد. مانند BRA loopstart
یک برچسب همراه با یک عبارت DAT به عنوان یک متغیر عمل می‌کند، آن آدرس حافظه‌ای را که داده در آن ذخیره شده را برچسب‌گذاری می‌کند. مانند DAT1 یا number1 DAT
در این مثال زبان اسمبلی که از حفظیات و برچسب‌ها استفاده می‌کند، اگر یک دستورالعمل قبل از دستورالعمل HLT پایانی وارد شود سپس مکان آدرس با FIRST برچسب‌گذاری شده اکنون به جای ۰۸ در مکان آدرس ۰۹ باید باشد و دستورالعمل STA FIRST زمانی‌که برنامه اسمبل می‌شود به جای 308 (STA 08) به 309 (STA 09) تبدیل می‌شود.
از این رو برچسبها استفاده می‌شوند برای:
مشخص کردن یک دستورالعمل خاص به عنوان یک هدف برای یک دستورالعمل انشعاب.
مشخص کردن یک مکان حافظه به عنوان یک متغیر نامدار (با استفاده از DAT) و بطور اختیاری داده‌ها را در برنامه در زمان اسمبل کردن برای استفاده توسط برنامه، بارگذاری می‌کند (این استفاده تا زمانی‌که درنظر بگیرد که هیچ راهی برای اضافه کردن یک واحد به شمارنده نیست، مشخص نمی‌شود. ممکن است از کاربر خواسته شود که ۱ را در ابتدا وارد کند، اما بهتر است که این بارگذاری را در زمان اسمبل کردن با استفاده از دستور one DAT 1 ، داشته باشیم)
مثال
این برنامه یک ورودی از کاربر دریافت کرده و آن را تا صفر بطور کاهشی می‌شمارد.
INP
OUT // Initialize output
LOOP BRZ QUIT // If the accumulator value is 0, jump to the memory address labeled QUIT
SUB ONE // Label this memory address as LOOP, The instruction will then subtract the value stored at address ONE from the accumulator
OUT
BRA LOOP // Jump (unconditionally) to the memory address labeled LOOP
QUIT HLT // Label this memory address as QUIT
ONE DAT 1 // Store the value 1 in this memory address, and label it ONE (variable declaration)
این برنامه یک ورودی از کاربر گرفته، آن را مربع کرده، و پاسخ را برمی‌گرداند و سپس تکرار می‌کند. وارد کردن صفر منجر به اتمام برنامه خواهد شد. (نکته: یک ورودی که خروجی را به بیش از ۹۹۹ نگاشت دهد، باعث بروز یک خطا به دلیل محدودیت تعداد ۳ رقم LMC می‌شود).
START LDA ZERO // Initialize for multiple program run
STA RESULT
STA COUNT
INP // User provided input
BRZ END // Branch to program END if input = ۰
STA VALUE // Store input as VALUE
LOOP LDA RESULT // Load the RESULT
ADD VALUE // Add VALUE, the user provided input, to RESULT
STA RESULT // Store the new RESULT
LDA COUNT // Load the COUNT
ADD ONE // Add ONE to the COUNT
STA COUNT // Store the new COUNT
SUB VALUE // Subtract the user provided input VALUE from COUNT
BRZ ENDLOOP // If zero (VALUE has been added to RESULT by VALUE times), branch to ENDLOOP
BRA LOOP // Branch to LOOP to continue adding VALUE to RESULT
ENDLOOP LDA RESULT // Load RESULT
OUT // Output RESULT
BRA START // Branch to the START to initialize and get another input VALUE
END HLT // HALT - a zero was entered so done!
RESULT DAT // Computed result (defaults to 0)
COUNT DAT // Counter (defaults to 0)
ONE DAT 1 // Constant, value of 1
VALUE DAT // User provided input, the value to be squared (defaults to 0)
ZERO DAT // Constant, value of 0 (defaults to 0)
نکته: اگر بعد از دستور DAT داده‌ای نباشد آنگاه بطور پیش‌فرض عدد صفر در آدرس حافظه ذخیره می‌شود.
در مثال بالا، BRZ ENDLOOP وابسته به یک رفتار تعریف نشده است، از آنجایی که COUNT-VALUE می‌تواند منفی باشد، بعد از اینکه مقدار انباره undefined شد، نتیجه BRZ یا انشعاب می‌یابد یا هیچ (انباره می‌تواند صفر باشد، یا پوشیده شود). برای سازگاری کد با مشخصات، جایگزین کنید:
LDA COUNT // Load the COUNT
ADD ONE // Add ONE to the COUNT
STA COUNT // Store the new COUNT
SUB VALUE // Subtract the user provided input VALUE from COUNT
BRZ ENDLOOP // If zero (VALUE has been added to RESULT by VALUE times), branch to ENDLOOP
بوسیله نسخه پیش رو، که VALUE-COUNT جایگزین COUNT-VALUE شده اس، مطمئن می‌شویم که انباره هرگز پاریز نخواهد شد:
LDA COUNT // Load the COUNT
ADD ONE // Add ONE to the COUNT
STA COUNT // Store the new COUNT
LDA VALUE // Load the VALUE
SUB COUNT // Subtract COUNT from the user provided input VALUE
BRZ ENDLOOP // If zero (VALUE has been added to RESULT by VALUE times), branch to ENDLOOP
مثال دیگر quine است، کد ماشین خودش را چاپ می‌کند (چاپ کردن منبع غیرممکن است زیرا حروف نمی‌توانند به خروجی روند):
LOAD LDA 0 // Load position 0 into the accumulator. This line will be modified on each loop to load the next lines into the accumulator
OUT // Output the accumulators value. The accumulators value will be the line that was just loaded
SUB ONE // Subtract 1 from the value in the accumulator. This is so we can do the BRZ in the next step to see if we are on the last line in the program
BRZ ONE // If the previous subtraction has made the accumulator 0 (which means we had the value 001 in the accumulator), then branch to position ONE
LDA LOAD // Load the LOAD position into the accumulator, this is in preparation to increment the address digits for this position
ADD ONE // Increment the position digits for the LOAD line. The value currently in the accumulator would, if read as an instruction, load the next line into the accumulator, compared to the last line loaded
STA LOAD // Store the newly incremented LOAD line back in the LOAD position
BRA LOAD // Return back to the beginning of the loop
ONE DAT 1 // The variable 1. If read as an instruction, this will be interpreted as HLT/COB and will end the program
این کواین با استفاده از کد خوداصلاحگر کار می‌کند. مکان ۰ در هر تکرار اضافه می‌شود، آن خط کد را به خروجی برده، تا زمانی‌که خروجی کد ۱ شود، در این نقطه به مکان ONE پرش می‌کند. مکان ONE با یک ۰ شروع شده، بنابراین به عنوان یک دستور HALT/COB تفسیر می‌شود.
CARDboard Illustrative Aid to Computation (another instructional model)
TIS-100 (video game)