实现逻辑是这样的:0-8是内存地址,将程序计数器寄存器的值加上此值,pc自加1,自加1之后的PC就是加载地址,取出该内存单元的值,将其放入9-11位所表示的寄存器中,这个0-8,也就是能够表示一个9bit的地址,我们的内存是16位的,所以显然LDI指令只能对附近的一些内存单元进行操作,这在x86中也有体现,当时只是知道一些指令只能进行段内跳转,这还是相对跳转hhh,现在清楚了为什么是远眺转为什么是近跳转。“可以将它想想成 C 中有一个局部变 量,这变量是指向某些数据的指针”,C语言中的局部变量也是因为距离的原因不能作用于全局嘛??
voidread_image_file(FILE* file) { uint16_t origin; /* the origin tells us where in memory to place the image */ fread(&origin, sizeof(origin), 1, file);//用于打开和读取文件 origin = swap16(origin);//变换字节序,将我们物理机产生的小端数据转换为LC-3的大端
/* we know the maximum file size so we only need one fread */ uint16_t max_read = UINT16_MAX - origin;//计算出可以读取的最大字节数 uint16_t* p = memory + origin;//指针p指向程序入口 size_t read = fread(p, sizeof(uint16_t), max_read, file); //从输入流file中读取最多max_read个元素,并将他们存储在以p为起始地址的内存位置中,返回值是读取的元素数存储在read中。 /* swap to little endian */ while (read-- > 0) { *p = swap16(*p); ++p; } } uint16_tswap16(uint16_t x) {//变换大小端 return (x << 8) | (x >> 8); }
uint16_tmem_read(uint16_t address) { if (address == MR_KBSR) { if (check_key()) { memory[MR_KBSR] = (1 << 15); memory[MR_KBDR] = getchar(); } else { memory[MR_KBSR] = 0; } } return memory[address]; } //陷阱代码 enum { TRAP_GETC = 0x20, /* get character from keyboard, not echoed onto the terminal */ TRAP_OUT = 0x21, /* output a character */ TRAP_PUTS = 0x22, /* output a word string */ TRAP_IN = 0x23, /* get character from keyboard, echoed onto the terminal */ TRAP_PUTSP = 0x24, /* output a byte string */ TRAP_HALT = 0x25/* halt the program */ };
voiddisable_input_buffering() { hStdin = GetStdHandle(STD_INPUT_HANDLE); GetConsoleMode(hStdin, &fdwOldMode); /* save old mode */ fdwMode = fdwOldMode ^ ENABLE_ECHO_INPUT /* no input echo */ ^ ENABLE_LINE_INPUT; /* return when one or more characters are available */ SetConsoleMode(hStdin, fdwMode); /* set new mode */ FlushConsoleInputBuffer(hStdin); /* clear buffer */ }
enum { FL_POS = 1 << 0, /* P */ FL_ZRO = 1 << 1, /* Z */ FL_NEG = 1 << 2, /* N */ }; voidupdate_flags(uint16_t r) { if (reg[r] == 0) { reg[R_COND] = FL_ZRO; } elseif (reg[r] >> 15) /* a 1 in the left-most bit indicates negative */ { reg[R_COND] = FL_NEG; } else { reg[R_COND] = FL_POS; } }
voidread_image_file(FILE* file) { /* the origin tells us where in memory to place the image */ uint16_t origin; fread(&origin, sizeof(origin), 1, file); origin = swap16(origin);
/* we know the maximum file size so we only need one fread */ uint16_t max_read = UINT16_MAX - origin; uint16_t* p = memory + origin; size_t read = fread(p, sizeof(uint16_t), max_read, file);
/* swap to little endian */ while (read-- > 0) { *p = swap16(*p); ++p; } } intread_image(constchar* image_path) { FILE* file = fopen(image_path, "rb"); if (!file) { return0; }; read_image_file(file); fclose(file); return1; }
intmain(int argc, constchar* argv[]) { if (argc < 2) { /* show usage string */ printf("lc3 [image-file1] ...\n"); exit(2); }
for (int j = 1; j < argc; ++j) { if (!read_image(argv[j])) { printf("failed to load image: %s\n", argv[j]); exit(1); } } signal(SIGINT, handle_interrupt); disable_input_buffering();
/* since exactly one condition flag should be set at any given time, set the Z flag */ reg[R_COND] = FL_ZRO;
/* set the PC to starting position */ /* 0x3000 is the default */ enum { PC_START = 0x3000 }; reg[R_PC] = PC_START;
int running = 1; while (running) { /* FETCH */ uint16_t instr = mem_read(reg[R_PC]++); uint16_t op = instr >> 12;
switch (instr & 0xFF) { case TRAP_GETC: { reg[R_R0] = (uint16_t)getchar(); update_flags(R_R0); } break; case TRAP_OUT: { putc((char)reg[R_R0], stdout); fflush(stdout); } break; case TRAP_PUTS: { /* one char per word */ uint16_t* c = memory + reg[R_R0]; while (*c) { putc((char)*c, stdout); ++c; } fflush(stdout); } break; case TRAP_IN: { printf("Enter a character: "); char c = getchar(); putc(c, stdout); fflush(stdout); reg[R_R0] = (uint16_t)c; update_flags(R_R0); } break; case TRAP_PUTSP: { /* one char per byte (two bytes per word) here we need to swap back to big endian format */ uint16_t* c = memory + reg[R_R0]; while (*c) { char char1 = (*c) & 0xFF; putc(char1, stdout); char char2 = (*c) >> 8; if (char2) putc(char2, stdout); ++c; } fflush(stdout); } break; case TRAP_HALT: puts("HALT"); fflush(stdout); running = 0; break; }break; case OP_RES: case OP_RTI: default: abort(); break; } } restore_input_buffering(); }