이 구문은 MASM/TASM 구문이라고 추측합니다. 이러한 경우 mov di,col*8
에서
는
col
메모리 "변수"는 ... 상당히 가짜이다 (보다 정확하게
col
값으로 그
col
후 정의 된 메모리의 첫 번째 바이트의 메모리 어드레스를 갖는 "어셈블리 심볼은" 레이블, 귀하의 경우에는
dw 0
지시어 =>에 의해 정의 된 2 바이트가 0 값으로 생성됩니다). 16 비트 정수 값
col
스탠드
col
메모리 어드레스의 일부인
OFFSET
여기서
그럼 mov di,col
는 mov di,[col]
에 mov
instructionmov r16,r/m16
의 변형으로 또는 적절한 인텔 문법에 조립된다. 주소의 세그먼트 부분은 기본적으로 ds
에서 가져오고, ds
을 올바르게 앞에 설정 한 경우 mov
은 dw
에 의해 예약 된 해당 메모리에 도달합니다.
mov di, col*8
가 모호, 당신도 (OFFSET col)*8
주소에서 메모리를 가져 의미 mov di,[col*8]
으로 = 당신이 원하지 않는 어떤 것을 조립, 또는 mov di,[col] * 8
산술로, 메모리에서 가져온 값을 곱, 및 x86 CPU는 없습니다 수 그러한 지시. (32B) 모드에서 유효 mov eax,[ebx + esi*8]
같은 메모리 주소와 관련된 연산은 mov
지침에
mov di,[col]
shl di,3 ; di = di * 8
모든 "산술 같은"작업, 그리고 메모리를 의미 : 당신처럼 별도로 값의 산술 연산을 할 필요가 먼저 가져올 주소가 계산됩니다. 값으로 부호/제로 확장을 수행하는 movsx/movzx
명령어를 제외하고는 x86 CPU 제품군의 mov
명령어에 내장 된 값 자체에 대한 산술 연산은 없습니다. 다른 예외는 생각해 낼 수 없습니다. lodsb
과 같은 "문자열"명령어 군은 가져온 후에 포인터 값을 조정하지만, 값 자체는 조정되지 않고 포인터 만 조정됩니다.
실제 메모리 오프셋으로 계산하는 대신 lea
명령어를 사용하여 메모리 주소 산술 CPU 모듈을 사용하여 값으로 일부 산술 연산을 계산할 수 있습니다. 물론 특정 코드에서
그것을 업데이트 할에 아무것도 읽기/저장이 모든 시간을 미리 곱, 그리고 유지하기 위해 어떤 레지스터의 값을 유지하고, 단지 add xxx,8
을 더 최적 /기억으로부터. 마지막 수단으로 메모리를 사용하십시오. 모든 것을 레지스터에 맞출 수없는 경우에만 사용하십시오.
편집 : 소스를 조금 더 읽은 후 ...
코드를 작성하고 각 단계마다 디버깅을 계속 실행하는 것이 좋습니다.
int 21h
출력 루틴으로 직접 비디오 램 쓰기를 믹싱하는 순간, 아무 것도 쓸 수 없습니다.
모든 확장 ASCII 문자를 표시하려면 직접 쓰기가 유일한 선택입니다 (DOS는 10, 13 및 기타 제어 코드 값을 표시하지 않으므로 커서 이동과 같은 특별한 작업을 수행합니다. (새 줄, 탭), 경고음 등).
그리고 256 심볼을 원한다면 16x16 테이블이 완벽한 의미를 갖습니다.
그래서 처음 16 개의 확장 ASCII를 한 줄로 표시하여 코드를 작성해야합니다. 같은, 당신은 처음에 텍스트 모드의 설정을 추가하는 등 ...에 "명확한 화면"을 확장 플러스 당신이 확인할 수 있습니다 (16 개 문자 한 줄을 보여줍니다)
code segment
assume cs:code, ds:code
main:
jmp begin
; reserved for data in future
; top left corner of the table at [0, 4] position
TABLE_LEFT_TOP_OFFSET equ (4*80*2)
; the table will be 16x16, each element being 5x1
; total size = 80x16 = (will fit 80x25 text mode screen)
; element 5 chars as:
; symbol, space, first hex digit, second hex digit, space
begin:
mov ax,0B800h
mov es,ax ; es = text mode VRAM segment
; display 16 symbols (single row) on proper positions
mov di,TABLE_LEFT_TOP_OFFSET ; di = starting VRAM adr
xor dl,dl ; symbol value = 0
mov cx,16 ; loop counter
row_loop:
; show symbol + space
mov al,dl ; symbol ASCII
mov ah,4h ; colour attribute
mov es:[di],ax ; write symbol
mov al,' '
mov es:[di+2],ax ; write space after it
; advance loop for next symbol
inc dl
add di,5*2 ; move 5 chars forward
dec cx
jnz row_loop
; exit back to DOS
xor ah,ah ; ah = 0 - wait for key service
int 16h
int 20h ; terminate to DOS
code ends
end main
예상대로이 작동 확인 후 예상 모드 :
begin:
mov ax,3 ; ah = 0 (set gfx mode), al = 3
int 10h ; set VGA text mode 80x25 chars
컴파일 + 실행 + 작동 확인. 다음은 16 진수 추가 할 수 있습니다 .. 다시 작동 확인 + 실행 ...
...
xor dl,dl ; symbol value = 0
rows_loop:
mov cx,16 ; loop counter
...
및
...
; both dl and di are ready for next line
; so all is needed is just to loop until dl==0
test dl,dl ; until all 256 symbols were displayed
jnz rows_loop
; exit back to DOS
...
:
그럼 당신은 모두 256 개 개의 문자를 보여 16 행 루프를 추가 할 수 있습니다 표시. 당신이 만 0 ~ 255의 값을 알고, 당신이 완전히 루프/푸시/팝을 방지, 그냥 수행 간단한 두 자리 번역 할 수 있습니다
...
mov es:[di+2],ax ; write space after it
; show hexadecimal value of symbol - first digit
mov al,dl
shr al,4 ; al = upper 4 bits of dl (first hex digit)
add al,'0'
cmp al,'9'
jbe first_hex_digit_ok
add al,('A'-'0'-10) ; adjust it to A-F letter if needed
first_hex_digit_ok:
mov es:[di+4],ax ; write first hex digit
; show hexadecimal value of symbol - second digit
mov al,dl
and al,0Fh ; al = lower 4 bits of dl (second hex digit)
add al,'0'
cmp al,'9'
jbe second_hex_digit_ok
add al,('A'-'0'-10) ; adjust it to A-F letter if needed
second_hex_digit_ok:
mov es:[di+6],ax ; write second hex digit
; write space after that
mov al,' '
mov es:[di+8],ax ; write space after it
; advance loop for next symbol
inc dl
...
디버그 + 작동 확인 (실제로하지 않았다 그래서 나는 단지 내 코드가 작동되기를 바랍니다).
그런 다음 당신은 결과 코드에 좀 걸릴 수 있습니다, 당신은 모든 쓰기가 연속 es:[di] = word value
일처럼 알 수 있습니다, 그래서 당신은 첫 번째 후 최적화 된 코드처럼, 대신 di+?
변위 및 add di,5*2
제거하는 stosw
을 사용하여 시도 할 수 있습니다
...
; display 16 symbols (single row) on proper positions
mov di,TABLE_LEFT_TOP_OFFSET ; di = starting VRAM adr
xor dl,dl ; symbol value = 0
rows_loop:
mov cx,16 ; loop counter
row_loop:
; show symbol + space
mov al,dl ; symbol ASCII
mov ah,4h ; colour attribute for symbol
stosw ; write symbol
mov al,' '
stosw ; write space after it
; show hexadecimal value of symbol - first digit
mov ah,2h ; colour attribute for hex value
mov al,dl
shr al,4 ; al = upper 4 bits of dl (first hex digit)
add al,'0'
cmp al,'9'
jbe first_hex_digit_ok
add al,('A'-'0'-10) ; adjust it to A-F letter if needed
first_hex_digit_ok:
stosw ; write first hex digit
; show hexadecimal value of symbol - second digit
mov al,dl
and al,0Fh ; al = lower 4 bits of dl (second hex digit)
add al,'0'
cmp al,'9'
jbe second_hex_digit_ok
add al,('A'-'0'-10) ; adjust it to A-F letter if needed
second_hex_digit_ok:
stosw ; write second hex digit
; write space after that
mov al,' '
stosw ; write space after it
; advance loop for next symbol
inc dl
dec cx
jnz row_loop
; both dl and di are ready for next line
; so all is needed is just to loop until dl==0
test dl,dl ; until all 256 symbols were displayed
jnz rows_loop
...
을 그리고 마지막으로 당신은 한 행 전체 (80)를 채우는 때문에 (최종의 행 상황을 통해 특별한 아무것도하지 않는 행과 행 루프를 알 수 있습니다 : (플러스 I은 16 진수 값의 색상을 변경 첨가) 라인의 문자들, 그래서 "자동적으로"다음 라인으로 넘어 간다.) 그래서 당신은 cx
카운터를 완전히 제거 할 수있다. 단일 256 기호 루프 :
...
xor dl,dl ; symbol value = 0
symbol_loop:
; show symbol + space
...
...
stosw ; write space after it
; advance loop for next symbol
inc dl
jnz symbol_loop ; until all 256 symbols are displayed
; exit back to DOS
...
그리고 그게 전부입니다. 나는 코드를 검증하지 않았기 때문에 약간의 버그가 생기면 유감스럽게 생각하지만 asm 코드를 작성할 때 생각하는 방식을 제시하려고 노력하고있다 ... 실제로 헥사 숫자를 사용하는 단계는 너무 컸다. 아마도 첫 번째 숫자 만 먼저 수행하고 +'0'
+'A'-'0'-10
이 예상대로 작동하는지 확인한 다음 두 번째 숫자를 추가합니다. 또한 코드가 최종 버전 (예 : x86 ASM 환경으로 인해)에서 어떻게 끝날지에 대한 명확한 비전이 있었기 때문에 es:di
과 같은 내 레지스터 사용 선택 사항 중 많은 부분이 매우 간단한 행운으로 보일 수 있습니다. 나중에 "무료".x86 어셈블리를 처음 사용하는 경우 초기 버전 코드 이후에 더 좋은 아이디어를 찾고 더 많은 내용을 덮어 쓰지 않으려면 개발 단계를 디버그 + 변경 사항을 한 번에 확인할 수있을 정도로 작게 유지하십시오.
이
mov byte ptr es:[di+2],s[0]
한쪽 등록하거나 즉시해야하며, 86 CPU에 mov
의 더 mov mem, mem
변형 없습니다 : 다른 문제를 칠 것입니다 현재 코드
.
일시적 값을 보유 할 AL
레지스터를 사용하는 것과 같이,이 mov
들에 그 분할해야 할 것 :
소스를 확인하기 위해
http://x86.renejeschke.de/ 같은 명령 참조 가이드를 사용하여
mov al,s[0]
mov es:[di+2],al
보관할는 일부 기존의 변종을 표적으로한다 명령이 어떻게 작동하는지 완벽하게 이해하고 있어야합니다 (특히 mul/imul
및 div/idiv
지침은 스택 오버플로에 대해 많은 질문을 제기하기 때문에 상식적으로 작동하지 않으므로 참조 안내서를 먼저 확인하면 쉽게 피할 수 있음).
어셈블리 프로그램과 C의 관계는 무엇입니까? – StoryTeller
실제로 메모리에 '8'을 저장하는 대신 'col * 8'을 즉각적으로 사용할 수있게하려면'col equ 8'을 사용하십시오. 당신은 무엇이든 'si'를 사용하지 않는 것 같습니다. 변수를 정적 저장소 대신 레지스터에 보관하십시오. 또한 1 씩 증가시키고 8을 곱하는 대신 8 씩 증가시킵니다. 즉, 열 값을 이미 크기 조정합니다. –