3

単純なスタックベースのマシンを作成する必要があります。命令セットは 5 つの命令で構成されています。プッシュ、ポップ、追加、マルチ、エンド。命令セクション (.text) とデータ セクション (.data) を持つソース コード ファイルを受け入れ、32 ビット アドレスを使用するメモリ システムをシミュレートして、これらをメモリに格納する必要があります。

メモリに保存する必要があるソース コード ファイルの例は、次のようになります。

    .text
main:
    push X
    push Y
    add   //remove top two words in stack and add them then put result on top of stack
    pop (some memory address)  // stores result in the address
    end

    .data
X:  3    // allocate memory store the number 3
Y:  5

メモリシステムの実行方法に関する提案はありますか? おそらくデータをあるセクション (おそらく配列?) に格納し、次に命令を別のセクションに格納する必要がありますが、コードで 32 ビット アドレスを使用する必要があるため、配列インデックスだけを使用することはできません。

編集:番号3と5をメモリ内(データ配列内)のスペースに割り当てたら、XとYを実際のアドレスに置き換える方法はありますか? . . . 2 パスのアセンブラーがそれを行うようなものです。

4

3 に答える 3

2

メモリ システムの鍵は、メモリの範囲を制限することです。OS では、メモリのいくつかのセクションにしかアクセスできません。

したがって、特定のプログラムでは、有効なプログラムには 0x00004000 で始まるアドレスを含めることができ、マシンで使用できるメモリはたとえば 4 MB であると言えます。

次に、プログラムで、サイズが 4MB の仮想メモリ空​​間を作成し、それを保存します。

以下は例です。これは一例であることを念頭に置いてください。それに応じてパラメータを調整する必要があります。

virtual memory start - 0x00006000 (get from malloc, or static initialization. or whatever)
stack machine memory start - 0x00004000
offset - 0x2000 (to align addresses in you OS and in your stack machine, you have to add 0x2000 to the stack machine address to get pointer to your array (in reality the offset can be negative).

実際に配列へのインデックスが必要な場合は、ポインタから仮想メモリの先頭を差し引くだけです。

于 2013-09-23T09:08:52.243 に答える
2

ウゴレンの答え(および少しOT)に追加するだけで、比較的興味深いアプローチは.stack、デフォルトで空に初期化されるセクションで仕様空間を拡張することだと思います(あなたの例のように)。

これは、予想される計算の中間段階を記述するために使用できます (ある時点で実際の状態を保存/復元します)。

実装するには、次のような非常に単純なコードを使用します

ファイル stack.h:

#ifndef STACK
#define STACK

#include <stdio.h>

/* here should be implemented the constraint about 32 bits words... */
typedef int word;

typedef struct { int top; word* mem; int allocated; } stack;
typedef stack* stackp;

stackp new_stack();
void free_stack(stackp);

void push(stackp s, word w);
word pop(stackp p);

/* extension */
stackp read(FILE*);
void write(stackp, FILE*);

#endif

ファイル stack.c:

/* example implementation, use - arbitrary - chunks of 2^N */

#include <stdlib.h>
#include "stack.h"

/* blocks are 256 words */
#define N (1 << 8)

stackp new_stack() {
  stackp s = calloc(1, sizeof(stack));
  s->mem = malloc((s->allocated = N) * sizeof(word));
  return s;
}
void free_stack(stackp s) {
  free(s->mem);
  free(s);
}

void push(stackp s, int w) {
  if (s->top == s->allocated) {
     s->allocated += N;
     s->mem = realloc(s->mem, s->allocated * sizeof(word));
  }
  s->mem[s->top++] = w;
}
word pop(stackp s) {
  if (s->top == 0) { /* exception */ }
  return s->mem[--(s->top)];
}

ファイル main.c:

#include "stack.h"
int main() {

  stackp s = new_stack();
  word X = 3;
  word Y = 5;

  push(s, X);
  push(s, Y);
  word Z = pop(s) + pop(s);

  printf("Z=%d\n", Z);

  free_stack(s);
}

ファイルメイクファイル:

main: main.c stack.c

構築する:

make

テストする:

./main
Z=8

いくつかの違いに注目する価値があります WRT ugoren の回答:データの隠蔽、実装の貴重な部分を強調し、実際の関数に関する詳細を別のファイルに保持します。そこでは、たとえば最大スタック サイズ (実際には強制されていません)、エラー処理など、多くの詳細を追加できます...

edit : プッシュされた単語の「アドレス」を取得する

word push(stackp s, int w) {
  if (s->top == s->allocated) {
     s->allocated += N;
     s->mem = realloc(s->mem, s->allocated * sizeof(word));
  }
  s->mem[s->top] = w;
  return s->top++;
}
于 2013-09-23T08:02:50.323 に答える