Assembly Language Programming

November 6, 2013

FASM – 6502 Assembly Language Simulator – Part 2

See also FASM – 6502 Assembly Language Simulator – Part 1

The FASM x86 code for the 6502 assembly language simulator.

; -------------------------------------------------------------------------------------

 format PE GUI 4.0

 entry start

 include 'win32a.inc'

; -------------------------------------------------------------------------------------

 IDD_EDIT_DIALOG = 102
 IDD_RUN_DIALOG = 103
 IDD_WATCH_DIALOG = 104

 IDC_INPUT = 1000
 IDC_OUTPUT = 1001
 IDC_STATUS = 1002
 IDC_PAGES = 1003
 IDC_DEBUG = 1004

 IDC_BTN_COMPILE = 1005
 IDC_BTN_VIEW_ASM = 1006
 IDC_BTN_VIEW_SYM = 1007
 IDC_BTN_CLR_ASM = 1008
 IDC_BTN_NEXT_DLG = 1009

 IDC_BTN_RUN = 1010
 IDC_BTN_STEP = 1011
 IDC_BTN_RESET_PC = 1012
 IDC_BTN_RESET = 1013
 IDC_BTN_PREV_DLG = 1014

 IDC_CBX_PAGE_SELECT = 1015

 IDC_BTN_LOAD_ASC = 1016
 IDC_BTN_ADD_WATCH = 1017
 IDC_BTN_VIEW_WATCH = 1018
 IDC_ASCII_IO = 1019

 IDC_GRP_BOX = 1020
 IDC_PROMPT_1 = 1021
 IDC_PROMPT_2 = 1022
 IDC_WATCH_ITEM = 1023
 IDC_WATCH_NBYTES = 1024
 IDC_BTN_ADD = 1025
 IDC_BTN_CLOSE = 1026

; -------------------------------------------------------------------------------------

 section '.code' code readable executable

  start:

	stdcall Reset_Machine

	stdcall Reset_Edit_Buffers

  edit_dlg:

	invoke GetModuleHandle,0

	invoke DialogBoxParam,eax,IDD_EDIT_DIALOG,0,DialogProc_Edit,0

	jmp next_dlg

  run_dlg:

	invoke GetModuleHandle,0

	invoke DialogBoxParam,eax,IDD_RUN_DIALOG,0,DialogProc_Run,0

  next_dlg:

	cmp [Next_Dlg_ID],byte 0

	je exit

	cmp [Next_Dlg_ID],byte 1

	je edit_dlg

	cmp [Next_Dlg_ID],byte 2

	je run_dlg

  exit:

	invoke	ExitProcess,0

; -------------------------------------------------------------------------------------

proc DialogProc_Edit uses esi edi ebx,hwnddlg,msg,wparam,lparam

  ; dialog proc for the EDIT dialog

	cmp [msg],WM_INITDIALOG

	je .wminitdialog

	cmp [msg],WM_COMMAND

	je .wmcommand

	cmp [msg],WM_CLOSE

	je .wmclose

	xor eax,eax

	jmp .quit

  .wminitdialog:

	invoke SetDlgItemText,[hwnddlg],IDC_INPUT,bfAsmCode

	invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,bfOutput

	jmp .done

  .wmcommand:

	cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_COMPILE

	je .COMPILE

	cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_VIEW_ASM

	je .VIEW_ASM

	cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_VIEW_SYM

	je .VIEW_SYM

	cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_CLR_ASM

	je .CLEAR_ASM

	cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_NEXT_DLG

	je .NEXT_DLG

	jmp .done

  .COMPILE:

	stdcall Reset_Watch_Arr

	invoke GetDlgItemText,[hwnddlg],IDC_INPUT,bfAsmCode,32768

	invoke GetDlgItemText,[hwnddlg],IDC_INPUT,bfDisplay,32768

	stdcall Compile

	cmp eax,0xffffffff

	je .PRINT_ERR

	jmp .SKIP

  .PRINT_ERR:

	stdcall Print_Compile_Error

  .SKIP:

	invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,bfOutput

	jmp .done

  .VIEW_ASM:

	invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,bfOutput

	jmp .done

  .VIEW_SYM:

	stdcall Print_Symbol_Table

	invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,bfDisplay

	jmp .done

  .CLEAR_ASM:

	mov [bfAsmCode],byte 0

	mov [bfOutput],byte 0

	invoke SetDlgItemText,[hwnddlg],IDC_INPUT,szInputText

	invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,""

	jmp .done

  .NEXT_DLG:

	invoke EndDialog,[hwnddlg],0

	mov [Next_Dlg_ID],byte 2

	jmp .done

  .wmclose:

	invoke EndDialog,[hwnddlg],0

	mov [Next_Dlg_ID],byte 0

  .done:

	mov eax,1

  .quit:

	ret

endp

; -------------------------------------------------------------------------------------

proc DialogProc_Run uses esi edi ebx,hwnddlg,msg,wparam,lparam

  ; dialog proc for the RUN dialog

	locals

	  index db 0

	endl

	cmp [msg],WM_INITDIALOG

	je .wminitdialog

	cmp [msg],WM_COMMAND

	je .wmcommand

	cmp [msg],WM_CLOSE

	je .wmclose

	xor eax,eax

	jmp .quit

  .wminitdialog:

	mov byte [Watch_On],0

	; fill the combo-box

	invoke GetDlgItem,[hwnddlg],IDC_CBX_PAGE_SELECT

	mov [hCBX],eax

  .FILL_CB:

	mov cl,[index]

	stdcall Set_CB_String

	invoke SendMessage,[hCBX],CB_ADDSTRING,NULL,cbString

	inc byte [index]

	cmp [index],byte 128

	jb .FILL_CB

	invoke SendMessage,[hCBX],CB_SETCURSEL,0,0

	xor ecx,ecx

	xor edx,edx

	stdcall Print_Page

	invoke SetDlgItemText,[hwnddlg],IDC_PAGES,bfDisplay

	stdcall Print_Status

	invoke SetDlgItemText,[hwnddlg],IDC_STATUS,bfDisplay

	invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,bfOutput

	invoke SetDlgItemText,[hwnddlg],IDC_DEBUG,""

	stdcall Init_ASC

	invoke SetDlgItemText,[hwnddlg],IDC_ASCII_IO,bfDisplay

	jmp .done

  .wmcommand:

	cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_RUN

	je .RUN

	cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_STEP

	je .STEP

	cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_RESET_PC

	je .PC

	cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_RESET

	je .RESET_MACHINE

	cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_PREV_DLG

	je .PREV_DLG

	cmp  [wparam], CBN_SELENDOK shl 16 + IDC_CBX_PAGE_SELECT

	je .VIEW_PAGE

	cmp  [wparam], BN_CLICKED shl 16 + IDC_BTN_ADD_WATCH

	je .ADD_TO_WATCH

	cmp  [wparam], BN_CLICKED shl 16 + IDC_BTN_VIEW_WATCH

	je .VIEW_WATCH

	cmp  [wparam], BN_CLICKED shl 16 + IDC_BTN_LOAD_ASC

	je .LOAD_ASC

	jmp .done

  .ADD_TO_WATCH:

	invoke GetModuleHandle,0

	invoke DialogBoxParam,eax,IDD_WATCH_DIALOG,0,DialogProc_Watch,0

	; if the bfDisplay buffer is empty, do nothing

	cmp byte [bfDisplay],0

	je .VIEW_PAGE

	stdcall Add_To_Watch

	cmp eax,0xffffffff

	jne .VIEW_WATCH

	stdcall Print_Watch_Error

	invoke SetDlgItemText,[hwnddlg],IDC_PAGES,bfDisplay

	jmp .done

  .LOAD_ASC:

	invoke GetDlgItemText,[hwnddlg],IDC_ASCII_IO,bfDisplay,2000

	stdcall Load_ASC

	jmp .VIEW_PAGE

  .VIEW_WATCH:

	mov byte [Watch_On],1

	stdcall Print_Watch

	invoke SetDlgItemText,[hwnddlg],IDC_PAGES,bfDisplay

	stdcall Print_ASC

	invoke SetDlgItemText,[hwnddlg],IDC_ASCII_IO,bfDisplay

	jmp .done

  .RUN:

	stdcall Run

	cmp eax,0xffffffff

	je .EXE_ERROR

	stdcall Print_Status

	invoke SetDlgItemText,[hwnddlg],IDC_STATUS,bfDisplay

	stdcall Print_Last_Exe_Info

	invoke SetDlgItemText,[hwnddlg],IDC_DEBUG,bfDisplay

	cmp byte [Watch_On],1

	je .VIEW_WATCH

	jmp .VIEW_PAGE

  .STEP:

	stdcall Step

	cmp eax,0xffffffff

	je .EXE_ERROR

	stdcall Print_Status

	invoke SetDlgItemText,[hwnddlg],IDC_STATUS,bfDisplay

	stdcall Print_Last_Exe_Info

	invoke SetDlgItemText,[hwnddlg],IDC_DEBUG,bfDisplay

	cmp byte [Watch_On],1

	je .VIEW_WATCH

	jmp .VIEW_PAGE

  .PC:

	; reset the program counter

	mov [Program_Counter],word 0x200

	stdcall Print_Status

	invoke SetDlgItemText,[hwnddlg],IDC_STATUS,bfDisplay

	jmp .done

  .RESET_MACHINE:

	mov byte [Watch_On],0

	stdcall Reset_Machine

	stdcall Reset_Watch_Arr

	xor ecx,ecx

	xor edx,edx

	stdcall Print_Page

	invoke SetDlgItemText,[hwnddlg],IDC_PAGES,bfDisplay

	stdcall Print_Status

	invoke SetDlgItemText,[hwnddlg],IDC_STATUS,bfDisplay

	invoke SetDlgItemText,[hwnddlg],IDC_DEBUG,""

	stdcall Init_ASC

	invoke SetDlgItemText,[hwnddlg],IDC_ASCII_IO,bfDisplay

	jmp .done

  .VIEW_PAGE:

	invoke SendMessage,[hCBX],CB_GETCURSEL,0,0

	mov edx,eax

	shl edx,9

	stdcall Print_Page

	invoke SetDlgItemText,[hwnddlg],IDC_PAGES,bfDisplay

	stdcall Print_ASC

	invoke SetDlgItemText,[hwnddlg],IDC_ASCII_IO,bfDisplay

	mov byte [Watch_On],0

	jmp .done

  .EXE_ERROR:

	stdcall Print_Exe_Error

	invoke SetDlgItemText,[hwnddlg],IDC_DEBUG,bfDisplay

	jmp .done

  .PREV_DLG:

	invoke EndDialog,[hwnddlg],0

	mov [Next_Dlg_ID],byte 1

	jmp .done

  .wmclose:

	invoke EndDialog,[hwnddlg],0

	mov [Next_Dlg_ID],byte 0

  .done:

	mov eax,1

  .quit:

	ret

endp

; -------------------------------------------------------------------------------------

proc DialogProc_Watch uses esi edi ebx,hwnddlg,msg,wparam,lparam

  ; dialog proc for the ADD WATCH dialog

	cmp [msg],WM_INITDIALOG

	je .wminitdialog

	cmp [msg],WM_COMMAND

	je .wmcommand

	cmp [msg],WM_CLOSE

	je .wmclose

	xor eax,eax

	jmp .quit

  .wminitdialog:

	invoke SetDlgItemText,[hwnddlg],IDC_WATCH_ITEM,""

	invoke SetDlgItemText,[hwnddlg],IDC_WATCH_NBYTES,""

	; initialise bfDisplay to an empty string

	; if the dialog exits and bfDisplay is still empty, do nothing

	lea esi,[bfDisplay]

	mov [esi],byte 0

	jmp .done

  .wmcommand:

	cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_ADD

	je .ADD

	cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_CLOSE

	je .CLOSE

	jmp .done

  .ADD:

	lea esi,[bfDisplay]

	; get the symbol or hex address

	invoke GetDlgItemText,[hwnddlg],IDC_WATCH_ITEM,esi,20

	; if the bfDisplay buffer is empty, just exit

	cmp byte [esi],0

	je .CLOSE

  .FIND_T:

	cmp [esi],byte 0

	je .NEXT

	inc esi

	jmp .FIND_T

  .NEXT:

	; insert a comma between the symbol/address and the number of bytes

	mov [esi],byte ','

	inc esi

	; get the number of bytes

	invoke GetDlgItemText,[hwnddlg],IDC_WATCH_NBYTES,esi,10

  .CLOSE:

  .wmclose:

	invoke EndDialog,[hwnddlg],0

  .done:

	mov eax,1

  .quit:

	ret

endp

; -------------------------------------------------------------------------------------

macro PRINT_CRLF
{
  mov [edi],byte 13
  inc edi

  mov [edi],byte 10
  inc edi
}

; -------------------------------------------------------------------------------------

proc Run

  ; run the program

	lea esi,[Main_Memory]

	xor ecx,ecx

	mov cx,[Program_Counter]

  .LOOP:

	mov al,[esi+ecx]

	cmp al,0

	je .BRK

	stdcall Execute_Instruction

	cmp eax,0xffffffff

	je .STOP

	jmp .LOOP

  .BRK:

	inc cx

  .STOP:

	mov [Program_Counter],cx

	ret

endp

; -------------------------------------------------------------------------------------

proc Step

  ; execute a single instruction (pointed to by the program counter)

	lea esi,[Main_Memory]

	xor ecx,ecx

	mov cx,[Program_Counter]

	mov al,[esi+ecx]

	cmp al,0

	je .BRK

	stdcall Execute_Instruction

	jmp .STOP

  .BRK:

	inc cx

  .STOP:

	mov [Program_Counter],cx

	ret

endp

; -------------------------------------------------------------------------------------

proc Compile

  ; compile the 6502 code

  ; pass 1 = build the symbol table

  ; pass 2 = assemble the instructions

	stdcall Reset_Machine

	mov [Debug_Code],word 0

	stdcall Reset_Symbol_Pointer

	stdcall Reset_Output

	; reset the program counter

	mov [Program_Counter],word 0x200

  .PASS_1:

	; ================================================

	mov [Location_Counter],word 0x200

	lea esi,[bfDisplay]

	; ================================================

	; Pass 1

	; get the next line

  .NEXT_LINE:

	cmp [esi],byte 0

	je .PASS_2

	stdcall Get_Next_Line

	cmp eax,0xffffffff

	je .DONE

	stdcall Check_Line

	cmp al,0

	je .NEXT_LINE

	stdcall Extract_Fields

	cmp eax,0xffffffff

	je .DONE

	stdcall Replace_Mnemonic

	stdcall Process_Labels_PsOps_1

	; no further processing of the line is required if EAX = 1

	cmp eax,1

	je .NEXT_LINE

	cmp eax,0xffffffff

	je .DONE

	stdcall Get_Operand_Size

	cmp eax,0xffffffff

	je .DONE

	stdcall Process_Instruction

	cmp eax,0xffffffff

	je .DONE

	jmp .NEXT_LINE

  .PASS_2:

	; ================================================

	mov [Location_Counter],word 0x200

	lea esi,[bfDisplay]

	; ================================================

	; Pass 2

	; get the next line

  .NEXT_LINE_2:

	cmp [esi],byte 0

	je .DONE

	stdcall Get_Next_Line

	cmp eax,0xffffffff

	je .DONE

	stdcall Check_Line

	cmp al,0

	je .NEXT_LINE_2

	stdcall Extract_Fields

	cmp eax,0xffffffff

	je .DONE

	stdcall Replace_Mnemonic

	stdcall Write_LC_To_Output

	cmp eax,0xffffffff

	je .DONE

	stdcall Process_Labels_PsOps_2

	cmp eax,0xffffffff

	je .DONE

	; no further processing of the line is required if EAX = 1

	cmp eax,1

	je .NEXT_LINE_2

	stdcall Calc_Addr_Mode

	cmp eax,0xffffffff

	je .DONE

	stdcall Calc_Operand

	cmp eax,0xffffffff

	je .DONE

	stdcall Assemble_Instruction

	cmp eax,0xffffffff

	je .DONE

	stdcall Write_Asm_To_Output

	cmp eax,0xffffffff

	je .DONE

	jmp .NEXT_LINE_2

	; ================================================

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Get_Next_Line uses edi

  ; get the next line from the input stream ESI

  ; ESI is set outside of this proc

	lea edi,[bfCurrentLine]

	xor ecx,ecx

  .COPY:

	; copy from ESI until a null or CRLF is read

	mov al,[esi]

	cmp al,0

	je .NULL_T

	cmp al,10

	je .NEXT_LINE

	cmp al,13

	je .NEXT_LINE

	cmp al,0x22

	je .SUB_ASC

	cmp al,0x27

	je .SUB_ASC

	; convert all letters to upper case

	stdcall Char_To_Upper

	mov [edi],al

	inc esi

	inc edi

	inc cx

	; if 128 chars were read, the line is too long

	cmp cx,128

	je .ERROR

	jmp .COPY

  .SUB_ASC:

	; replace a char constant (enclosed by ' ' or " ") with it's ascii code

	; ascii code written as a 2 digit hex value: $xx

	mov [edi],byte '$'

	inc esi

	inc edi

	inc cx

	cmp cx,128

	je .ERROR

	; read the char

	mov al,[esi]

	cmp al,0

	je .ERROR_2

	; get the ascii value

	stdcall Byte_To_Hex

	; write the first hex digit

	mov [edi],ah

	inc edi

	inc cx

	cmp cx,128

	je .ERROR

	; write the second hex digit

	mov [edi],al

	inc edi

	inc cx

	cmp cx,128

	je .ERROR

	inc esi

	mov al,[esi]

	inc esi

	cmp al,0x22

	je .COPY

	cmp al,0x27

	je .COPY

	jmp .ERROR_2

  .NEXT_LINE:

	; increment ESI past the CRLF

	inc esi

	mov al,[esi]

	cmp al,10

	je .NEXT_LINE

	cmp al,13

	je .NEXT_LINE

  .NULL_T:

	mov [edi],byte 0

	lea edi,[bfCurrentLine]

  .DISCARD:

	; if there is a comment, discard the rest of the line

	cmp [edi],byte 0

	je .DONE

	cmp [edi],byte ';'

	jne .NEXT

	; null terminate at the ';'

	mov [edi],byte 0

	jmp .DONE

  .NEXT:

	inc edi

	jmp .DISCARD

  .ERROR:

	; input line must be less than 128 chars

	mov eax,0xffffffff

	mov [Debug_Code],word 1

	jmp .DONE

  .ERROR_2:

	; invalid char in line

	mov eax,0xffffffff

	mov [Debug_Code],word 12

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Check_Line uses esi

  ; is the line empty ?

	xor eax,eax

	lea esi,[bfCurrentLine]

  .SCAN:

	cmp [esi],byte 0

	je .DONE

	cmp [esi],byte 32

	jg .NOT_BLANK

	inc esi

	jmp .SCAN

  .NOT_BLANK:

	mov al,1

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Extract_Fields uses esi edi ecx

  ; extract the label, mnemonic and operand from the current line

	lea esi,[bfCurrentLine]

	xor ecx,ecx

	; clear the operand buffer

	lea edi,[bfOperand]

	mov [edi],byte 0

	; clear the mnemonic buffer

	lea edi,[bfMnemonic]

	mov [edi],byte 0

	; clear the label buffer

	lea edi,[bfLabel]

	mov [edi],byte 0

	; get the label (if any)

	; there is a label if the first column contains a non-whitespace char

	cmp [esi],byte 32

	jg .GET_LABEL

	jmp .SKIP

  .GET_LABEL:

	; copy the label to bfLabel

	mov al,[esi]

	cmp al,0

	je .NULL_T

	cmp al,32

	je .NULL_T

	cmp al,9

	je .NULL_T

	mov [edi+ecx],al

	inc esi

	inc cx

	; maximum length of a label is 14 chars

	cmp cx,14

	jg .DEBUG_1

	jmp .GET_LABEL

  .NULL_T:

	mov [edi+ecx],byte 0

	; the label is now in bfLabel

	; does the label contain valid chars

	stdcall Validate_Label

	cmp eax,0xffffffff

	je .DONE

	cmp [esi],byte 0

	je .DONE

  .SKIP:

	; skip any whitespace to get to the mnemonic (if any)

	inc esi

	cmp [esi],byte 9

	je .SKIP

	cmp [esi],byte 32

	je .SKIP

	cmp [esi],byte 0

	je .DONE

  .GET_M:

	lea edi,[bfMnemonic]

	; get the mnemonic

	; letter 1:

	mov al,[esi]

	cmp al,'A'

	jl .DEBUG_2

	cmp al,'Z'

	jg .DEBUG_2

	mov [edi],al

	inc esi

	; letter 2:

	mov al,[esi]

	cmp al,'A'

	jl .DEBUG_2

	cmp al,'Z'

	jg .DEBUG_2

	mov [edi+1],al

	inc esi

	; letter 3:

	mov al,[esi]

	cmp al,'A'

	jl .DEBUG_2

	cmp al,'Z'

	jg .DEBUG_2

	mov [edi+2],al

	mov [edi+3],byte 0

	inc esi

	; next char in input stream must be a space or null terminator

	cmp [esi],byte 9

	je .SKIP_2

	cmp [esi],byte 32

	je .SKIP_2

	cmp [esi],byte 0

	je .DONE

	jmp .DEBUG_4

  .SKIP_2:

	; skip any whitespace to get to the operand (if any)

	inc esi

	cmp [esi],byte 9

	je .SKIP_2

	cmp [esi],byte 32

	je .SKIP_2

	cmp [esi],byte 0

	je .DONE

	; get the operand

	lea edi,[bfOperand]

	xor ecx,ecx

  .GET_OPERAND:

	mov al,[esi]

	cmp al,0

	je .NULL_T_2

	cmp al,9

	je .NULL_T_2

	cmp al,32

	je .NULL_T_2

	mov [edi+ecx],al

	inc esi

	inc cx

	; operand can contain a maximum of 111 chars

	cmp cx,111

	jg .DEBUG_3

	jmp .GET_OPERAND

  .NULL_T_2:

	mov [edi+ecx],byte 0

	cmp al,0

	je .DONE

  .EXTRA:

	; test for extra chars on the line

	inc esi

	cmp [esi],byte 9

	je .EXTRA

	cmp [esi],byte 32

	je .EXTRA

	cmp [esi],byte 0

	je .DONE

	; if the code reaches this point there are extra chars

  .DEBUG_0:

	; extra chars in the line

	mov [Debug_Code],word 2

	jmp .ERROR

  .DEBUG_1:

	; label was found to contain more than 14 chars

	mov [Debug_Code],word 3

	jmp .ERROR

  .DEBUG_2:

	; invalid chars in the mnemonic

	mov [Debug_Code],word 4

	jmp .ERROR

  .DEBUG_3:

	; operand field must be less than 112 chars

	mov [Debug_Code],word 5

	jmp .ERROR

  .DEBUG_4:

	; too many chars in the mnemonic field

	mov [Debug_Code],word 6

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Replace_Mnemonic uses esi

  ; replace if the mnemonic field contains: BGE, BLT, BTR, BFL, XOR

  ; BGE = BCS
  ; BLT = BCC
  ; BTR = BEQ
  ; BFL = BNE
  ; XOR = EOR

	lea esi,[bfMnemonic]

	cmp [esi],byte 'B'

	jne .XOR

	cmp [esi+1],byte 'G'

	je .BGE

	cmp [esi+1],byte 'L'

	je .BLT

	cmp [esi+1],byte 'T'

	je .BTR

	cmp [esi+1],byte 'F'

	je .BFL

	jmp .DONE

  .BGE:

	cmp [esi+2],byte 'E'

	jne .DONE

	; replace with BCS

	mov [esi],dword 0x00534342

	jmp .DONE

  .BLT:

	cmp [esi+2],byte 'T'

	jne .DONE

	; replace with BCC

	mov [esi],dword 0x00434342

	jmp .DONE

  .BTR:

	cmp [esi+2],byte 'R'

	jne .DONE

	; replace with BEQ

	mov [esi],dword 0x00514542

	jmp .DONE

  .BFL:

	cmp [esi+2],byte 'L'

	jne .DONE

	; replace with BNE

	mov [esi],dword 0x00454E42

	jmp .DONE

  .XOR:

	cmp [esi],byte 'X'

	jne .DONE

	cmp [esi+1],byte 'O'

	jne .DONE

	cmp [esi+2],byte 'R'

	jne .DONE

	; replace with EOR

	mov [esi],dword 0x00524F45

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Process_Labels_PsOps_1 uses edi ecx edx

  ; compile = pass 1

  ; check bfMnemonic for the pseudo-ops: EQU, EPZ, DFS, ORG, HEX, ADR, BYT, HBY, DBY

	; put the mnemonic into EDX

	mov edx,dword [bfMnemonic]

	lea edi,[bfLabel]

	; is there a mnemonic ?

	cmp dl,0

	je .ADD_LABEL

  .A:

	cmp dl,'A'

	jne .B

	shr edx,8

	cmp dl,'D'

	jne .ADD_LABEL

	shr edx,8

	cmp dl,'R'

	jne .ADD_LABEL

	; check for a label

	cmp [edi],byte 0

	je .ADR

	stdcall Add_Label

	cmp eax,0xffffffff

	je .DONE

  .ADR:

	; there must be an operand

	stdcall Count_Expressions

	cmp eax,0

	je .DEBUG_3

	; reserve the bytes by incrementing the location counter

	; 2 bytes for every expression

	shl ax,1

	add [Location_Counter],ax

	mov eax,1

	jmp .DONE

  .B:

	cmp dl,'B'

	jne .E

	shr edx,8

	cmp dl,'Y'

	jne .ADD_LABEL

	shr edx,8

	cmp dl,'T'

	jne .ADD_LABEL

	; check for a label

	cmp [edi],byte 0

	je .BYT

	stdcall Add_Label

	cmp eax,0xffffffff

	je .DONE

  .BYT:

	; there must be an operand

	stdcall Count_Expressions

	cmp eax,0

	je .DEBUG_3

	; reserve the bytes by incrementing the location counter

	; 1 byte for every expression

	add [Location_Counter],ax

	mov eax,1

	jmp .DONE

  .E:

	cmp dl,'E'

	jne .D

	shr edx,8

  .EQU:

	; EQU

	cmp dl,'Q'

	jne .EPZ

	cmp dh,'U'

	jne .ADD_LABEL

	; there must be a label

	cmp [edi],byte 0

	je .DEBUG_1

	; there must be an operand

	stdcall Count_Expressions

	cmp eax,0

	je .DEBUG_3

	stdcall Read_Number

	cmp eax,0xffffffff

	je .DONE

	stdcall Add_Label_EQU

	cmp eax,0xffffffff

	je .DONE

	mov eax,1

	jmp .DONE

  .EPZ:

	; EPZ

	cmp dl,'P'

	jne .ADD_LABEL

	cmp dh,'Z'

	jne .ADD_LABEL

	; there must be a label

	cmp [edi],byte 0

	je .DEBUG_1

	; there must be an operand

	stdcall Count_Expressions

	cmp eax,0

	je .DEBUG_3

	stdcall Read_Number

	cmp eax,0xffffffff

	je .DONE

	cmp dx,255

	ja .DEBUG_2

	stdcall Add_Label_EQU

	cmp eax,0xffffffff

	je .DONE

	mov eax,1

	jmp .DONE

  .D:

	; DFS

	cmp dl,'D'

	jne .H

	shr edx,8

	cmp dl,'F'

	jne .DB

	cmp dh,'S'

	jne .ADD_LABEL

  .DFS:

	; there must be a label

	cmp [edi],byte 0

	je .DEBUG_1

	stdcall Add_Label

	cmp eax,0xffffffff

	je .DONE

	; there must be an operand

	stdcall Count_Expressions

	cmp eax,0

	je .DEBUG_3

	; read the operand to get the number of bytes to reserve

	stdcall Process_DFS

	cmp eax,0xffffffff

	je .DONE

	; reserve the bytes by incrementing the location counter

	add [Location_Counter],ax

	mov eax,1

	jmp .DONE

  .DB:

	cmp dl,'B'

	jne .ADD_LABEL

	cmp dh,'Y'

	jne .ADD_LABEL

	; check for a label

	cmp [edi],byte 0

	je .DBY

	stdcall Add_Label

	cmp eax,0xffffffff

	je .DONE

  .DBY:

	; there must be an operand

	stdcall Count_Expressions

	cmp eax,0

	je .DEBUG_3

	; reserve the bytes by incrementing the location counter

	; 2 bytes for every expression

	shl ax,1

	add [Location_Counter],ax

	mov eax,1

	jmp .DONE

  .H:

	cmp dl,'H'

	jne .O

	shr edx,8

	cmp dl,'B'

	jne .HEX

	shr edx,8

	cmp dl,'Y'

	jne .ADD_LABEL

	; check for a label

	cmp [edi],byte 0

	je .HBY

	stdcall Add_Label

	cmp eax,0xffffffff

	je .DONE

  .HBY:

	; there must be an operand

	stdcall Count_Expressions

	cmp eax,0

	je .DEBUG_3

	; reserve the bytes by incrementing the location counter

	; 1 byte for every expression

	add [Location_Counter],ax

	mov eax,1

	jmp .DONE

  .HEX:

	; HEX

	cmp dl,'E'

	jne .ADD_LABEL

	cmp dh,'X'

	jne .ADD_LABEL

	; check for a label

	cmp [edi],byte 0

	je .READ_H

	stdcall Add_Label

	cmp eax,0xffffffff

	je .DONE

  .READ_H:

	; there must be an operand

	stdcall Count_Expressions

	cmp eax,0

	je .DEBUG_3

	stdcall Read_Hex

	cmp eax,0xffffffff

	je .DONE

	; increment the location counter by the number of bytes read

	add [Location_Counter],cx

	mov eax,1

	jmp .DONE

  .O:

	; ORG

	cmp dl,'O'

	jne .ADD_LABEL

	shr edx,8

	cmp dl,'R'

	jne .ADD_LABEL

	cmp dh,'G'

	jne .ADD_LABEL

	; check for a label

	cmp [edi],byte 0

	je .READ_ORG

	stdcall Add_Label

	cmp eax,0xffffffff

	je .DONE

  .READ_ORG:

	; there must be an operand

	stdcall Count_Expressions

	cmp eax,0

	je .DEBUG_3

	stdcall Process_ORG

	cmp eax,0xffffffff

	je .DONE

	mov eax,1

	jmp .DONE

  .ADD_LABEL:

	; check for a label

	cmp [edi],byte 0

	je .DONE

	stdcall Add_Label

	cmp eax,0xffffffff

	je .DONE

	mov eax,0

	jmp .DONE

  .DEBUG_1:

	; no label found for EQU, EPZ or DFS

	mov [Debug_Code],word 7

	jmp .ERROR

  .DEBUG_2:

	; operand for EPZ must evaluate to a 1 byte value

	mov [Debug_Code],word 8

	jmp .ERROR

  .DEBUG_3:

	; all pseudo ops must have an operand

	mov [Debug_Code],word 41

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Add_Label_EQU uses esi edi ebx ecx

  ; add bfLabel to the symbol table and assign it the value passed in DX

	lea esi,[bfLabel]

	lea edi,[Main_Memory]

	; symbol table starts on page 252

	add edi,64512

	xor ecx,ecx

	; test against each entry in the symbol table

	; pSymbol_Table points to just after the last symbol in the table

	mov ebx,[pSymbol_Table]

	; if EBX = EDI at this point, the symbol table is empty

	cmp ebx,edi

	je .ADD

  .TEST:

	; compare bfLabel to the entry in the symbol table

	mov al,[esi+ecx]

	cmp al,[edi+ecx]

	jne .NEXT

	cmp al,0

	je .ERROR

	inc ecx

	cmp ecx,14

	jle .TEST

  .ERROR:

	; the label matches an existing symbol

	mov eax,0xffffffff

	mov [Debug_Code],word 9

	jmp .DONE

  .NEXT:

	xor ecx,ecx

	; entry in symbol table is 16 bytes

	add edi,16

	cmp edi,ebx

	je .ADD

	jmp .TEST

  .ADD:

	; add the label

	mov al,[esi+ecx]

	mov [edi+ecx],al

	cmp al,0

	je .SET

	inc cx

	jmp .ADD

  .SET:

	mov [edi+14],dx

  .INCREMENT:

	stdcall Increment_Symbol_Pointer

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Add_Label uses esi edi ebx ecx

  ; add bfLabel to the symbol table

	lea esi,[bfLabel]

	lea edi,[Main_Memory]

	; symbol table starts on page 252

	add edi,64512

	xor ecx,ecx

	; test against each entry in the symbol table

	; pSymbol_Table points to just after the last symbol in the table

	mov ebx,[pSymbol_Table]

	; if EBX = EDI at this point, the symbol table is empty

	cmp ebx,edi

	je .ADD

  .TEST:

	; compare bfLabel to the entry in the symbol table

	mov al,[esi+ecx]

	cmp al,[edi+ecx]

	jne .NEXT

	cmp al,0

	je .ERROR

	inc ecx

	cmp ecx,14

	jle .TEST

  .ERROR:

	; the label matches an existing symbol

	mov eax,0xffffffff

	mov [Debug_Code],word 10

	jmp .DONE

  .NEXT:

	xor ecx,ecx

	; entry in symbol table is 16 bytes

	add edi,16

	cmp edi,ebx

	je .ADD

	jmp .TEST

  .ADD:

	; add the label

	mov al,[esi+ecx]

	mov [edi+ecx],al

	cmp al,0

	je .SET

	inc cx

	jmp .ADD

  .SET:

	; use the location counter to set the value of the label

	mov dx,[Location_Counter]

	mov [edi+14],dx

  .INCREMENT:

	stdcall Increment_Symbol_Pointer

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Count_Expressions uses esi

  ; for the ADR, DBY, BYT, HBY, DFS, ORG pseudo ops

  ; count the number of expressions in the operand

  ; return count in EAX

	lea esi,[bfOperand]

	xor eax,eax

	cmp [esi],byte 0

	je .DONE

	mov eax,1

  .SCAN:

	; count the commas

	inc esi

	cmp [esi],byte 0

	je .DONE

	cmp [esi],byte ','

	jne .SCAN

	inc eax

	jmp .SCAN

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Process_Labels_PsOps_2 uses edi ecx edx

  ; compile = pass 2

  ; check bfMnemonic for the pseudo-ops: EQU, EPZ, DFS, ORG, HEX, ADR, BYT, HBY, DBY

	lea edi,[bfMnemonic]

	; put the mnemonic into EDX

	mov edx,[edi]

	lea edi,[bfLabel]

	; is there a mnemonic ?

	cmp dl,0

	; if not, do nothing

	je .DONE

  .A:

	cmp dl,'A'

	jne .B

	shr edx,8

	cmp dl,'D'

	jne .DONE

	shr edx,8

	cmp dl,'R'

	jne .DONE

  .ADR:

	stdcall Process_ADR

	cmp eax,0xffffffff

	je .DONE

	stdcall Write_Line_To_Output

	cmp eax,0xffffffff

	je .DONE

	mov eax,1

	jmp .DONE

  .B:

	cmp dl,'B'

	jne .E

	shr edx,8

	cmp dl,'Y'

	jne .DONE

	shr edx,8

	cmp dl,'T'

	jne .DONE

  .BYT:

	stdcall Process_BYT

	cmp eax,0xffffffff

	je .DONE

	stdcall Write_Line_To_Output

	cmp eax,0xffffffff

	je .DONE

	mov eax,1

	jmp .DONE

  .E:

	cmp dl,'E'

	jne .D

	shr edx,8

  .EQU:

	; EQU

	cmp dl,'Q'

	jne .EPZ

	cmp dh,'U'

	jne .DONE

	; do nothing - EQU was processed in pass 1

	stdcall Write_Line_To_Output

	cmp eax,0xffffffff

	je .DONE

	mov eax,1

	jmp .DONE

  .EPZ:

	; EPZ

	cmp dl,'P'

	jne .DONE

	cmp dh,'Z'

	jne .DONE

	; do nothing - EPZ was processed in pass 1

	stdcall Write_Line_To_Output

	cmp eax,0xffffffff

	je .DONE

	mov eax,1

	jmp .DONE

  .D:

	; DFS

	cmp dl,'D'

	jne .H

	shr edx,8

	cmp dl,'F'

	jne .DBY

	cmp dh,'S'

	jne .DONE

	; read the operand to get the number of bytes to reserve

	stdcall Process_DFS

	cmp eax,0xffffffff

	je .DONE

	; reserve and initialise the bytes

	stdcall Init_DFS

	stdcall Write_Line_To_Output

	cmp eax,0xffffffff

	je .DONE

	mov eax,1

	jmp .DONE

  .DBY:

	cmp dl,'B'

	jne .DONE

	cmp dh,'Y'

	jne .DONE

	stdcall Process_DBY

	cmp eax,0xffffffff

	je .DONE

	stdcall Write_Line_To_Output

	cmp eax,0xffffffff

	je .DONE

	mov eax,1

	jmp .DONE

  .H:

	cmp dl,'H'

	jne .O

	shr edx,8

	cmp dl,'B'

	jne .HEX

	shr edx,8

	cmp dl,'Y'

	jne .DONE

  .HBY:

	stdcall Process_HBY

	cmp eax,0xffffffff

	je .DONE

	stdcall Write_Line_To_Output

	cmp eax,0xffffffff

	je .DONE

	mov eax,1

	jmp .DONE

  .HEX:

	; HEX

	cmp dl,'E'

	jne .DONE

	cmp dh,'X'

	jne .DONE

  .READ_H:

	stdcall Read_Hex

	cmp eax,0xffffffff

	je .DONE

	; write the bytes to memory

	stdcall Store_Hex

	stdcall Write_Line_To_Output

	cmp eax,0xffffffff

	je .DONE

	mov eax,1

	jmp .DONE

  .O:

	; ORG

	cmp dl,'O'

	jne .DONE

	shr edx,8

	cmp dl,'R'

	jne .DONE

	cmp dh,'G'

	jne .DONE

  .READ_ORG:

	stdcall Process_ORG

	cmp eax,0xffffffff

	je .DONE

	stdcall Write_Line_To_Output

	cmp eax,0xffffffff

	je .DONE

	mov eax,1

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Process_ORG uses esi edi ecx

  ; process the ORG pseudo op

  ; operand contains a single expression

	lea esi,[bfOperand]

	lea edi,[bfExpression]

  .COPY:

	; copy the expression from the operand

	mov al,[esi]

	cmp al,0

	je .CALC

	mov [edi],al

	inc esi

	inc edi

	jmp .COPY

  .CALC:

	; compute the value of the expression

	mov [edi],byte 0

	stdcall Calc_Expression

	cmp eax,0xffffffff

	je .DONE

	; set the location counter

	mov [Location_Counter],ax

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Process_ADR uses esi edi ecx

  ; process the ADR pseudo op

  ; operand may contain a single expression or a comma delimited list of expressions

	lea esi,[bfOperand]

	lea edi,[bfExpression]

  .EXTRACT:

	; extract the expressions from the operand

	mov al,[esi]

	cmp al,0

	je .CALC

	cmp al,','

	je .CALC

	mov [edi],al

	inc esi

	inc edi

	jmp .EXTRACT

  .CALC:

	; compute the value of the expression

	mov [edi],byte 0

	stdcall Calc_Expression

	cmp eax,0xffffffff

	je .DONE

	; write the 2 byte value to memory

	mov dx,ax

	mov cl,2

	stdcall Store_Hex

	; is there another expression ?

	cmp [esi],byte ','

	jne .DONE

	inc esi

	lea edi,[bfExpression]

	jmp .EXTRACT

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Process_DBY uses esi edi ecx

  ; process the DBY pseudo op

  ; operand may contain a single expression or a comma delimited list of expressions

	lea esi,[bfOperand]

	lea edi,[bfExpression]

  .EXTRACT:

	; extract the expressions from the operand

	mov al,[esi]

	cmp al,0

	je .CALC

	cmp al,','

	je .CALC

	mov [edi],al

	inc esi

	inc edi

	jmp .EXTRACT

  .CALC:

	; compute the value of the expression

	mov [edi],byte 0

	stdcall Calc_Expression

	cmp eax,0xffffffff

	je .DONE

	; write the 2 byte value to memory

	; high byte first

	mov dl,ah

	; then the low byte

	mov dh,al

	mov cl,2

	stdcall Store_Hex

	; is there another expression ?

	cmp [esi],byte ','

	jne .DONE

	inc esi

	lea edi,[bfExpression]

	jmp .EXTRACT

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Process_BYT uses esi edi

  ; process the BYT pseudo op

  ; operand may contain a single expression or a comma delimited list of expressions

	lea esi,[bfOperand]

	lea edi,[bfExpression]

  .EXTRACT:

	; extract the expressions from the operand

	mov al,[esi]

	cmp al,0

	je .CALC

	cmp al,','

	je .CALC

	mov [edi],al

	inc esi

	inc edi

	jmp .EXTRACT

  .CALC:

	; compute the value of the expression

	mov [edi],byte 0

	stdcall Calc_Expression

	cmp eax,0xffffffff

	je .DONE

	; write the low byte of the 2 byte value to memory

	mov dl,al

	mov cl,1

	stdcall Store_Hex

	; is there another expression ?

	cmp [esi],byte ','

	jne .DONE

	inc esi

	lea edi,[bfExpression]

	jmp .EXTRACT

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Process_HBY uses esi edi

  ; process the HBY pseudo op

  ; operand may contain a single expression or a comma delimited list of expressions

	lea esi,[bfOperand]

	lea edi,[bfExpression]

  .EXTRACT:

	; extract the expressions from the operand

	mov al,[esi]

	cmp al,0

	je .CALC

	cmp al,','

	je .CALC

	mov [edi],al

	inc esi

	inc edi

	jmp .EXTRACT

  .CALC:

	; compute the value of the expression

	mov [edi],byte 0

	stdcall Calc_Expression

	cmp eax,0xffffffff

	je .DONE

	; write the high byte of the 2 byte value to memory

	mov dl,ah

	mov cl,1

	stdcall Store_Hex

	; is there another expression ?

	cmp [esi],byte ','

	jne .DONE

	inc esi

	lea edi,[bfExpression]

	jmp .EXTRACT

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Process_DFS uses esi edi ebx

  ; process the DFS pseudo op

  ; operand can contain up to 2 expressions (comma delimited)

  ; first expression gives the number of bytes to reserve

  ; second expression gives a byte value to which the reserved bytes are initialised

	lea esi,[bfOperand]

	lea edi,[bfExpression]

  .EXTRACT:

	; extract the first expression from the operand

	mov al,[esi]

	cmp al,0

	je .CALC

	cmp al,','

	je .CALC

	mov [edi],al

	inc esi

	inc edi

	jmp .EXTRACT

  .CALC:

	; compute the value of the expression = number of bytes to reserve

	mov [edi],byte 0

	stdcall Calc_Expression

	cmp eax,0xffffffff

	je .DONE

	; is there another expression ?

	cmp [esi],byte ','

	jne .DONE

	mov ebx,eax

	inc esi

	lea edi,[bfExpression]

  .EXTRACT_2:

	; extract the second expression from the operand (if any)

	mov al,[esi]

	cmp al,0

	je .INIT

	cmp al,','

	je .INIT

	mov [edi],al

	inc esi

	inc edi

	jmp .EXTRACT_2

  .INIT:

	; the low byte value of this expression is used to init the reserved bytes

	mov [edi],byte 0

	stdcall Calc_Expression

	cmp eax,0xffffffff

	je .DONE

	bswap eax

	mov ax,bx

	; number of bytes to reserve in now in AX

	; init byte value is in the upper byte of EAX

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Init_DFS uses edi ebx ecx

  ; init the bytes reserved by the DFS pseudo op

  ; the init byte value is passed in the upper byte of EAX

	lea edi,[Main_Memory]

	xor ebx,ebx

	mov bx,[Location_Counter]

	mov cx,ax

	; put the byte value into AL

	bswap eax

  .INIT:

	mov [edi+ebx],al

	inc ebx

	dec cx

	cmp cx,0

	je .DONE

	jmp .INIT

  .DONE:

	mov word [Location_Counter],bx

	ret

endp

; -------------------------------------------------------------------------------------

proc Process_Instruction uses edi

  ; compile - pass 1

  ; use the mnemonic and operand size to increment the location counter

	; the operand size is passed in AL

	locals

	  op_size db 0

	  addr_mode db 0

	endl

	; get the addressing mode

	stdcall Calc_Addr_Mode

	mov byte [addr_mode],dl

	; the location counter

	mov cx,[Location_Counter]

	mov [op_size],al

	; put the mnemonic into EAX

	mov eax,dword [bfMnemonic]

	; is there anything in the mnemonic field ?

	cmp al,0

	je .DONE

	lea edi,[Main_Memory]

	cmp al,'A'

	je .A

	cmp al,'B'

	je .B

	cmp al,'C'

	je .C

	cmp al,'D'

	je .D

	cmp al,'E'

	je .E

	cmp al,'I'

	je .I

	cmp al,'J'

	je .J

	cmp al,'L'

	je .L

	cmp al,'N'

	je .N

	cmp al,'O'

	je .O

	cmp al,'P'

	je .P

	cmp al,'R'

	je .R

	cmp al,'S'

	je .S

	cmp al,'T'

	je .T

	jmp .FAILED

  .A:

	shr eax,8

  .AND:

	cmp al,'N'

	jne .ADC

	shr eax,8

	cmp al,'D'

	jne .FAILED

	; operand size cannot be 0 bytes

	cmp [op_size],byte 0

	je .ERROR

	; zp,y not supported by AND, will be assembled as a,y (3 bytes)

	cmp byte [addr_mode],4

	jne .ADD_OP_SIZE

	add cx,3

	jmp .DONE

  .ADC:

	cmp al,'D'

	jne .ASL

	shr eax,8

	cmp al,'C'

	jne .FAILED

	; operand size cannot be 0 bytes

	cmp [op_size],byte 0

	je .ERROR

	; zp,y not supported by ADC, will be assembled as a,y (3 bytes)

	cmp byte [addr_mode],4

	jne .ADD_OP_SIZE

	add cx,3

	jmp .DONE

  .ASL:

	cmp al,'S'

	jne .FAILED

	shr eax,8

	cmp al,'L'

	jne .FAILED

	; operand size can be 0, 1 or 2 bytes

	jmp .ADD_OP_SIZE

  .B:

	shr eax,8

  .BRK:

	cmp al,'R'

	jne .BCC

	shr eax,8

	cmp al,'K'

	jne .FAILED

	; operand size should be 0 bytes

	cmp [op_size],byte 0

	jne .ERROR

	; size of assembled instruction is 1 byte

	inc cx

	jmp .DONE

  .BCC:

	cmp al,'C'

	jne .BIT

	shr eax,8

	cmp al,'C'

	jne .BCS

	; operand size should be 2 bytes

	cmp [op_size],byte 2

	jne .ERROR

	; size of assembled instruction is 2 bytes

	add cx,2

	jmp .DONE

  .BCS:

	cmp al,'S'

	jne .FAILED

	; operand size should be 2 bytes

	cmp [op_size],byte 2

	jne .ERROR

	; size of assembled instruction is 2 bytes

	add cx,2

	jmp .DONE

  .BIT:

	cmp al,'I'

	jne .BEQ

	shr eax,8

	cmp al,'T'

	jne .FAILED

	; operand size cannot be 0 bytes

	cmp [op_size],byte 0

	je .ERROR

	jmp .ADD_OP_SIZE

  .BEQ:

	cmp al,'E'

	jne .BMI

	shr eax,8

	cmp al,'Q'

	jne .FAILED

	; operand size should be 2 bytes

	cmp [op_size],byte 2

	jne .ERROR

	; size of assembled instruction is 2 bytes

	add cx,2

	jmp .DONE

  .BMI:

	cmp al,'M'

	jne .BNE

	shr eax,8

	cmp al,'I'

	jne .FAILED

	; operand size should be 2 bytes

	cmp [op_size],byte 2

	jne .ERROR

	; size of assembled instruction is 2 bytes

	add cx,2

	jmp .DONE

  .BNE:

	cmp al,'N'

	jne .BPL

	shr eax,8

	cmp al,'E'

	jne .FAILED

	; operand size should be 2 bytes

	cmp [op_size],byte 2

	jne .ERROR

	; size of assembled instruction is 2 bytes

	add cx,2

	jmp .DONE

  .BPL:

	cmp al,'P'

	jne .BVC

	shr eax,8

	cmp al,'L'

	jne .FAILED

	; operand size should be 2 bytes

	cmp [op_size],byte 2

	jne .ERROR

	; size of assembled instruction is 2 bytes

	add cx,2

	jmp .DONE

  .BVC:

	cmp al,'V'

	jne .FAILED

	shr eax,8

	cmp al,'C'

	jne .BVS

	; operand size should be 2 bytes

	cmp [op_size],byte 2

	jne .ERROR

	; size of assembled instruction is 2 bytes

	add cx,2

	jmp .DONE

  .BVS:

	cmp al,'S'

	jne .FAILED

	; operand size should be 2 bytes

	cmp [op_size],byte 2

	jne .ERROR

	; size of assembled instruction is 2 bytes

	add cx,2

	jmp .DONE

  .C:

	shr eax,8

  .CLC:

	cmp al,'L'

	jne .CMP

	shr eax,8

	cmp al,'C'

	jne .CLV

	; operand size should be 0 bytes

	cmp [op_size],byte 0

	jne .ERROR

	; size of assembled instruction is 1 byte

	inc cx

	jmp .DONE

  .CLV:

	cmp al,'V'

	jne .FAILED

	; operand size should be 0 bytes

	cmp [op_size],byte 0

	jne .ERROR

	; size of assembled instruction is 1 byte

	inc cx

	jmp .DONE

  .CMP:

	cmp al,'M'

	jne .CPX

	shr eax,8

	cmp al,'P'

	jne .FAILED

	; operand size cannot be 0 bytes

	cmp [op_size],byte 0

	je .ERROR

	; zp,y not supported by CMP, will be assembled as a,y (3 bytes)

	cmp byte [addr_mode],4

	jne .ADD_OP_SIZE

	add cx,3

	jmp .DONE

  .CPX:

	cmp al,'P'

	jne .FAILED

	shr eax,8

	cmp al,'X'

	jne .CPY

	; operand size cannot be 0 bytes

	cmp [op_size],byte 0

	je .ERROR

	jmp .ADD_OP_SIZE

  .CPY:

	cmp al,'Y'

	jne .FAILED

	; operand size cannot be 0 bytes

	cmp [op_size],byte 0

	je .ERROR

	jmp .ADD_OP_SIZE

  .D:

	shr eax,8

  .DEC:

	cmp al,'E'

	jne .FAILED

	shr eax,8

	cmp al,'C'

	jne .DEX

	; operand size cannot be 0 bytes

	cmp [op_size],byte 0

	je .ERROR

	jmp .ADD_OP_SIZE

  .DEX:

	cmp al,'X'

	jne .DEY

	; operand size should be 0 bytes

	cmp [op_size],byte 0

	jne .ERROR

	; size of assembled instruction is 1 byte

	inc cx

	jmp .DONE

  .DEY:

	cmp al,'Y'

	jne .FAILED

	; operand size should be 0 bytes

	cmp [op_size],byte 0

	jne .ERROR

	; size of assembled instruction is 1 byte

	inc cx

	jmp .DONE

  .E:

	shr eax,8

  .EOR:

	cmp al,'O'

	jne .FAILED

	shr eax,8

	cmp al,'R'

	jne .FAILED

	; operand size cannot be 0 bytes

	cmp [op_size],byte 0

	je .ERROR

	; zp,y not supported by EOR, will be assembled as a,y (3 bytes)

	cmp byte [addr_mode],4

	jne .ADD_OP_SIZE

	add cx,3

	jmp .DONE

  .I:

	shr eax,8

  .INC:

	cmp al,'N'

	jne .FAILED

	shr eax,8

	cmp al,'C'

	jne .INX

	; operand size cannot be 0 bytes

	cmp [op_size],byte 0

	je .ERROR

	jmp .ADD_OP_SIZE

  .INX:

	cmp al,'X'

	jne .INY

	; operand size should be 0 bytes

	cmp [op_size],byte 0

	jne .ERROR

	; size of assembled instruction is 1 byte

	inc cx

	jmp .DONE

  .INY:

	cmp al,'Y'

	jne .FAILED

	; operand size should be 0 bytes

	cmp [op_size],byte 0

	jne .ERROR

	; size of assembled instruction is 1 byte

	inc cx

	jmp .DONE

  .J:

	shr eax,8

  .JMP:

	cmp al,'M'

	jne .JSR

	shr eax,8

	cmp al,'P'

	jne .FAILED

	; operand size cannot be 0

	cmp [op_size],byte 0

	je .ERROR

	; size of assembled instruction is 3 bytes

	add cx,3

	jmp .DONE

  .JSR:

	cmp al,'S'

	jne .FAILED

	shr eax,8

	cmp al,'R'

	jne .FAILED

	; operand size should be 2 bytes

	cmp [op_size],byte 2

	jne .ERROR

	; size of assembled instruction is 3 bytes

	add cx,3

	jmp .DONE

  .L:

	shr eax,8

  .LDA:

	cmp al,'D'

	jne .LSR

	shr eax,8

	cmp al,'A'

	jne .LDX

	; operand size cannot be 0 bytes

	cmp [op_size],byte 0

	je .ERROR

	; zp,y not supported by LDA, will be assembled as a,y (3 bytes)

	cmp byte [addr_mode],4

	jne .ADD_OP_SIZE

	add cx,3

	jmp .DONE

  .LDX:

	cmp al,'X'

	jne .LDY

	; operand size cannot be 0 bytes

	cmp [op_size],byte 0

	je .ERROR

	jmp .ADD_OP_SIZE

  .LDY:

	cmp al,'Y'

	jne .FAILED

	; operand size cannot be 0 bytes

	cmp [op_size],byte 0

	je .ERROR

	jmp .ADD_OP_SIZE

  .LSR:

	cmp al,'S'

	jne .FAILED

	shr eax,8

	cmp al,'R'

	jne .FAILED

	; operand size can be 0, 1 or 2 bytes

	jmp .ADD_OP_SIZE

  .N:

	shr eax,8

  .NOP:

	cmp al,'O'

	jne .FAILED

	shr eax,8

	cmp al,'P'

	jne .FAILED

	; operand size should be 0 bytes

	cmp [op_size],byte 0

	jne .ERROR

	; size of assembled instruction is 1 byte

	inc cx

	jmp .DONE

  .O:

	shr eax,8

  .ORA:

	cmp al,'R'

	jne .FAILED

	shr eax,8

	cmp al,'A'

	jne .FAILED

	; operand size cannot be 0 bytes

	cmp [op_size],byte 0

	je .ERROR

	; zp,y not supported by ORA, will be assembled as a,y (3 bytes)

	cmp byte [addr_mode],4

	jne .ADD_OP_SIZE

	add cx,3

	jmp .DONE

  .P:

	shr eax,8

  .PHA:

	cmp al,'H'

	jne .PLA

	shr eax,8

	cmp al,'A'

	jne .PHP

	; operand size should be 0 bytes

	cmp [op_size],byte 0

	jne .ERROR

	; size of assembled instruction is 1 byte

	inc cx

	jmp .DONE

  .PHP:

	cmp al,'P'

	jne .FAILED

	; operand size should be 0 bytes

	cmp [op_size],byte 0

	jne .ERROR

	; size of assembled instruction is 1 byte

	inc cx

	jmp .DONE

  .PLA:

	cmp al,'L'

	jne .FAILED

	shr eax,8

	cmp al,'A'

	jne .PLP

	; operand size should be 0 bytes

	cmp [op_size],byte 0

	jne .ERROR

	; size of assembled instruction is 1 byte

	inc cx

	jmp .DONE

  .PLP:

	cmp al,'P'

	jne .FAILED

	; operand size should be 0 bytes

	cmp [op_size],byte 0

	jne .ERROR

	; size of assembled instruction is 1 byte

	inc cx

	jmp .DONE

  .R:

	shr eax,8

  .ROL:

	cmp al,'O'

	jne .RTS

	shr eax,8

	cmp al,'L'

	jne .ROR

	; operand size can be 0, 1 or 2 bytes

	jmp .ADD_OP_SIZE

  .ROR:

	cmp al,'R'

	jne .FAILED

	; operand size can be 0, 1 or 2 bytes

	jmp .ADD_OP_SIZE

  .RTS:

	cmp al,'T'

	jne .FAILED

	shr eax,8

	cmp al,'S'

	jne .FAILED

	; operand size should be 0 bytes

	cmp [op_size],byte 0

	jne .ERROR

	; size of assembled instruction is 1 byte

	inc cx

	jmp .DONE

  .S:

	shr eax,8

  .STA:

	cmp al,'T'

	jne .SBC

	shr eax,8

	cmp al,'A'

	jne .STX

	; operand size cannot be 0 bytes

	cmp [op_size],byte 0

	je .ERROR

	; zp,y not supported by STA, will be assembled as a,y (3 bytes)

	cmp byte [addr_mode],4

	jne .ADD_OP_SIZE

	add cx,3

	jmp .DONE

  .STX:

	cmp al,'X'

	jne .STY

	; operand size cannot be 0 bytes

	cmp [op_size],byte 0

	je .ERROR

	; a,y not supported by STX, will be assembled as zp,y (2 bytes)

	cmp byte [addr_mode],4

	jne .ADD_OP_SIZE

	add cx,2

	jmp .DONE

  .STY:

	cmp al,'Y'

	jne .FAILED

	; operand size cannot be 0 bytes

	cmp [op_size],byte 0

	je .ERROR

	; a,x not supported by STY, will be assembled as zp,x (2 bytes)

	cmp byte [addr_mode],3

	jne .ADD_OP_SIZE

	add cx,2

	jmp .DONE
  .SBC:

	cmp al,'B'

	jne .SEC

	shr eax,8

	cmp al,'C'

	jne .FAILED

	; operand size cannot be 0 bytes

	cmp [op_size],byte 0

	je .ERROR

	; zp,y not supported by SBC, will be assembled as a,y (3 bytes)

	cmp byte [addr_mode],4

	jne .ADD_OP_SIZE

	add cx,3

	jmp .DONE

  .SEC:

	cmp al,'E'

	jne .FAILED

	shr eax,8

	cmp al,'C'

	jne .FAILED

	; operand size should be 0 bytes

	cmp [op_size],byte 0

	jne .ERROR

	; size of assembled instruction is 1 byte

	inc cx

	jmp .DONE

  .T:

	shr eax,8

  .TAX:

	cmp al,'A'

	jne .TSX

	shr eax,8

	cmp al,'X'

	jne .TAY

	; operand size should be 0 bytes

	cmp [op_size],byte 0

	jne .ERROR

	; size of assembled instruction is 1 byte

	inc cx

	jmp .DONE

  .TAY:

	cmp al,'Y'

	jne .FAILED

	; operand size should be 0 bytes

	cmp [op_size],byte 0

	jne .ERROR

	; size of assembled instruction is 1 byte

	inc cx

	jmp .DONE

  .TSX:

	cmp al,'S'

	jne .TXA

	shr eax,8

	cmp al,'X'

	jne .FAILED

	; operand size should be 0 bytes

	cmp [op_size],byte 0

	jne .ERROR

	; size of assembled instruction is 1 byte

	inc cx

	jmp .DONE

  .TXA:

	cmp al,'X'

	jne .TYA

	shr eax,8

	cmp al,'A'

	jne .TXS

	; operand size should be 0 bytes

	cmp [op_size],byte 0

	jne .ERROR

	; size of assembled instruction is 1 byte

	inc cx

	jmp .DONE

  .TXS:

	cmp al,'S'

	jne .FAILED

	; operand size should be 0 bytes

	cmp [op_size],byte 0

	jne .ERROR

	; size of assembled instruction is 1 byte

	inc cx

	jmp .DONE

  .TYA:

	cmp al,'Y'

	jne .FAILED

	shr eax,8

	cmp al,'A'

	jne .FAILED

	; operand size should be 0 bytes

	cmp [op_size],byte 0

	jne .ERROR

	; size of assembled instruction is 1 byte

	inc cx

	jmp .DONE

  .ADD_OP_SIZE:

	; add the operand size to CX

	inc cx

	add cl,byte [op_size]

	adc ch,0

	jmp .DONE

  .FAILED:

	; unknown mnemonic

	mov [Debug_Code],word 17

	mov eax,0xffffffff

	jmp .DONE

  .ERROR:

	; invalid mnemonic and operand size combination

	mov [Debug_Code],word 18

	mov eax,0xffffffff

  .DONE:

	mov [Location_Counter],cx

	ret

endp

; -------------------------------------------------------------------------------------

proc Get_Operand_Size uses esi edi ecx

  ; determine the size of the value stored in the operand

  ; return in AL

	xor eax,eax

	xor ecx,ecx

	xor edx,edx

	lea esi,[bfOperand]

	; is the operand empty ?

	cmp [esi],byte 0

	je .DONE

	; test the first char from ESI

	cmp [esi],byte '#'

	je .1_BYTE

	cmp [esi],byte '/'

	je .1_BYTE

	cmp [esi],byte '('

	je .SCAN_IND

  .SCAN:

	cmp [esi],byte '*'

	je .2_BYTE

	cmp [esi],byte '$'

	je .SCAN_HEX

	cmp [esi],byte '!'

	je .INC_DEC

	cmp [esi],byte '%'

	je .SCAN_BIN

	cmp [esi],byte '0'

	jl .DEBUG_1

	cmp [esi],byte '9'

	jle .SCAN_DEC

	cmp [esi],byte 'A'

	jl .DEBUG_1

	cmp [esi],byte 'Z'

	jle .SCAN_LABEL

	; the first char in the operand is an invalid char

	jmp .DEBUG_1

  .SCAN_LABEL:

	; the first char in the operand is a letter = there is a symbol

	lea edi,[bfSymbol]

  .COPY:

	; read the symbol into bfSymbol

	mov dl,[esi]

	cmp dl,0

	je .NULL_T

	cmp dl,'+'

	je .NULL_T

	cmp dl,'-'

	je .NULL_T

	cmp dl,','

	je .NULL_T

	mov [edi],dl

	inc esi

	inc edi

	jmp .COPY

  .NULL_T:

	mov [edi],byte 0

	; see if there is a match for the symbol in the symbol table

	stdcall Lookup_Symbol

	; only symbols defined with EQU or EPZ are guaranteed to
	; be in the table at this point (pass 1)

	; if the symbol is not in the table, then it is assumed that it will
	; appear as the label for a line of code after the current line

	; therefore it will have a 2 byte value

	cmp eax,0xffffffff

	je .2_BYTE

	; the symbol was found, is it a ZP or absolute value ?

	cmp ah,0

	jg .2_BYTE

	cmp [esi],byte 0

	je .1_BYTE

	cmp [esi],byte ','

	je .1_BYTE

	; the symbol evaluates to a 1 byte value, but the argument
	; after the + or - might be 2 bytes

	cmp [esi],byte '+'

	je .PLUS

	cmp [esi],byte '-'

	je .MINUS

	jmp .DEBUG_1

  .SCAN_HEX:

	; if more than 2 hex digits have been read, then it's a 2 byte value

	cmp cx,2

	jg .2_BYTE

	inc esi

	; it's a 1 byte value if a null, comma, plus or minus char are found here

	cmp [esi],byte 0

	je .1_BYTE

	cmp [esi],byte ','

	je .1_BYTE

	cmp [esi],byte '+'

	je .PLUS

	cmp [esi],byte '-'

	je .MINUS

	cmp [esi],byte '0'

	jl .DEBUG_2

	cmp [esi],byte '9'

	jle .NEXT_H

	cmp [esi],byte 'A'

	jl .DEBUG_2

	cmp [esi],byte 'F'

	jle .NEXT_H

	; the hex number field contains an invalid char

	jmp .DEBUG_2

  .NEXT_H:

	inc cx

	jmp .SCAN_HEX

  .INC_DEC:

	inc esi

  .SCAN_DEC:

	; digit 1

	mov dl,[esi]

	cmp dl,'0'

	jl .DEBUG_3

	cmp dl,'9'

	jg .DEBUG_3

	inc esi

	; digit 2

	shl edx,8

	mov dl,[esi]

	cmp dl,0

	je .1_BYTE

	cmp dl,','

	je .1_BYTE

	cmp dl,'+'

	je .PLUS

	cmp dl,'-'

	je .MINUS

	cmp dl,'0'

	jl .DEBUG_3

	cmp dl,'9'

	jg .DEBUG_3

	inc esi

	; digit 3

	shl edx,8

	mov dl,[esi]

	cmp dl,0

	je .1_BYTE

	cmp dl,','

	je .1_BYTE

	cmp dl,'+'

	je .PLUS

	cmp dl,'-'

	je .MINUS

	cmp dl,'0'

	jl .DEBUG_3

	cmp dl,'9'

	jg .DEBUG_3

	inc esi

	; digit 4

	cmp [esi],byte 0

	je .CALC_D

	cmp [esi],byte '+'

	je .CALC_D

	cmp [esi],byte '-'

	je .CALC_D

	cmp [esi],byte ','

	je .CALC_D

	shl edx,8

	mov dl,[esi]

	cmp dl,'0'

	jl .DEBUG_3

	cmp dl,'9'

	jle .2_BYTE

  .CALC_D:

	stdcall Calc_Decimal

	cmp edx,255

	ja .2_BYTE

	cmp [esi],byte '+'

	je .PLUS

	cmp [esi],byte '-'

	je .MINUS

	jmp .1_BYTE

  .SCAN_BIN:

	; if more than 8 bin digits have been read, then it's a 2 byte value

	cmp cx,8

	jg .2_BYTE

	inc esi

	; it's a 1 byte value if a null, comma, plus or minus char are found here

	cmp [esi],byte 0

	je .1_BYTE

	cmp [esi],byte ','

	je .1_BYTE

	cmp [esi],byte '+'

	je .PLUS

	cmp [esi],byte '-'

	je .MINUS

	cmp [esi],byte '0'

	je .NEXT_B

	cmp [esi],byte '1'

	je .NEXT_B

	; the bin number field contains an invalid char

	jmp .DEBUG_4

  .NEXT_B:

	inc cx

	jmp .SCAN_BIN

  .PLUS:

	inc esi

	xor ecx,ecx

	jmp .SCAN

  .MINUS:

	inc esi

	xor ecx,ecx

	jmp .SCAN

  .SCAN_IND:

	inc esi

	; if a comma is found the mode is: (zp,x) or (zp),y

	cmp [esi],byte ','

	je .1_BYTE

	; if a comma is not found the mode is: (a)

	cmp [esi],byte 0

	je .2_BYTE

	jmp .SCAN_IND

  .1_BYTE:

	; operand contains a 1 byte value

	mov al,1

	jmp .DONE

  .2_BYTE:

	; operand contains a 2 byte value

	mov al,2

	jmp .DONE

  .DEBUG_1:

	; invalid char in operand

	mov [Debug_Code],word 12

	jmp .ERROR

  .DEBUG_2:

	; invalid char in hex number

	mov [Debug_Code],word 13

	jmp .ERROR

  .DEBUG_3:

	; invalid char in decimal number

	mov [Debug_Code],word 14

	jmp .ERROR

  .DEBUG_4:

	; invalid char in binary number

	mov [Debug_Code],word 15

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Validate_Label uses esi

  ; the first char in a label must be a letter

  ; a label can only contain letters, numbers and underscores

	; test the first char

	lea esi,[bfLabel]

	cmp [esi],byte 'A'

	jl .ERROR

	cmp [esi],byte 'Z'

	jg .ERROR

  .CHECK:

	inc esi

	cmp [esi],byte 0

	je .DONE

	cmp [esi],byte '_'

	je .CHECK

	cmp [esi],byte '0'

	jl .ERROR

	cmp [esi],byte '9'

	jle .CHECK

	cmp [esi],byte 'A'

	jl .ERROR

	cmp [esi],byte 'Z'

	jle .CHECK

  .ERROR:

	; label contains invalid chars

	mov [Debug_Code],word 16

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Calc_Addr_Mode uses esi

  ; detect the addressing mode of the operand

  ; result is returned in DX

  ; addressing mode in DL

  ; length of operand in DH

	lea esi,[bfOperand]

	xor edx,edx

  .LEN:

	cmp [esi],byte 0

	je .MODE

	inc dh

	inc esi

	jmp .LEN

  .MODE:

	; test for the modes:

	; ================================================

	; # = immediate (low byte) - mode = 1

	; / = immediate (high byte) - mode = 2

	; zp,x and a,x - mode = 3

	; zp,y and a,y - mode = 4

	; (zp,x) - mode = 5

	; (zp),y - mode = 6

	; (a) - mode = 7

	; all other modes - mode = 0

	; ================================================

	; is the length zero ?

	cmp dh,0

	je .DONE

	lea esi,[bfOperand]

	; detect immediate mode

	cmp [esi],byte '#'

	je .IMMED_LO

	; detect immediate mode

	cmp [esi],byte '/'

	je .IMMED_HI

	; detect indirect mode

	cmp [esi],byte '('

	je .SCAN_2

  .SCAN_1:

	inc esi

	cmp [esi],byte 0

	je .DONE

	; detect indexed mode

	cmp [esi],byte ','

	je .INDEXED

	jmp .SCAN_1

  .INDEXED:

	inc esi

	cmp [esi],byte 0

	je .ERROR

	; detect indexed by X mode - a,x and zp,x

	cmp [esi],byte 'X'

	jne .IS_Y

	mov dl,3

	jmp .DONE

  .IS_Y:

	; detect indexed by Y mode - a,y and zp,y

	cmp [esi],byte 'Y'

	jne .ERROR

	mov dl,4

	jmp .DONE

  .SCAN_2:

	inc esi

	cmp [esi],byte 0

	je .ERROR

	cmp [esi],byte ')'

	je .IS_IND_Y

	cmp [esi],byte ','

	je .IS_X

	jmp .SCAN_2

  .IS_X:

	inc esi

	; detect indexed by X indirect mode - (zp,x)

	cmp [esi],byte 'X'

	jne .ERROR

	mov dl,5

	jmp .DONE

  .IS_IND_Y:

	inc esi

	cmp [esi],byte ','

	jne .INDIRECT

	inc esi

	; detect indirect indexed by Y mode - (zp),y

	cmp [esi],byte 'Y'

	jne .INDIRECT

	mov dl,6

	jmp .DONE

  .INDIRECT:

	; indirect mode

	cmp [esi],byte 0

	jne .ERROR

	mov dl,7

	jmp .DONE

  .IMMED_LO:

	; immediate mode (low byte)

	mov dl,1

	jmp .DONE

  .IMMED_HI:

	; immediate mode (high byte)

	mov dl,2

	jmp .DONE

  .ERROR:

	mov [Debug_Code],word 31

	mov eax,0xffffffff

	jmp .DONE

  .DONE:

	; save the result

	lea esi,[Operand_Data]

	mov word [esi+2],dx

	ret

endp

; -------------------------------------------------------------------------------------

proc Calc_Operand uses esi edx

  ; compute the 1 or 2 byte value of the operand

  ; an operand can have 1 or 2 arguments

  ; if there are 2 arguments, they must be separated by a plus or minus

	lea esi,[bfOperand]

	xor eax,eax

	cmp [esi],byte 0

	je .DONE

	cmp [esi],byte '#'

	je .NEXT

	cmp [esi],byte '/'

	je .NEXT

	cmp [esi],byte '('

	je .NEXT

	jmp .FIRST

  .NEXT:

	inc esi

  .FIRST:

	; first argument

	stdcall Calc_Operand_Value

	cmp eax,0xffffffff

	je .DONE

	cmp [esi],byte '+'

	je .PLUS

	cmp [esi],byte '-'

	je .MINUS

	jmp .DONE

  .PLUS:

	xor edx,edx

	mov dx,ax

	inc esi

	; these chars are invalid if they appear after a plus or minus sign

	cmp [esi],byte 0

	je .ERROR

	cmp [esi],byte '#'

	je .ERROR

	cmp [esi],byte '/'

	je .ERROR

	cmp [esi],byte '('

	je .ERROR

	; second argument

	stdcall Calc_Operand_Value

	cmp eax,0xffffffff

	je .DONE

	add ax,dx

	jmp .DONE

  .MINUS:

	xor edx,edx

	mov dx,ax

	inc esi

	; these chars are invalid if they appear after a plus or minus sign

	cmp [esi],byte 0

	je .ERROR

	cmp [esi],byte '#'

	je .ERROR

	cmp [esi],byte '/'

	je .ERROR

	cmp [esi],byte '('

	je .ERROR

	; second argument

	stdcall Calc_Operand_Value

	cmp eax,0xffffffff

	je .DONE

	sub dx,ax

	mov ax,dx

	jmp .DONE

  .ERROR:

	; invalid chars after a plus or minus

	mov [Debug_Code],word 10

	mov eax,0xffffffff

  .DONE:

	; save the result

	lea esi,[Operand_Data]

	mov [esi],ax

	ret

endp

; -------------------------------------------------------------------------------------

proc Calc_Operand_Value

  ; extract an argument from the operand and calculate it's value

  ; an operand can have 1 or 2 arguments

  ; if there are 2 arguments they must be separated by a + or -

  ; the argument is read from ESI

  ; ESI is set outside of this proc

  ; return the 16-bit value in AX

	xor eax,eax

  .READ:

	cmp [esi],byte 0

	je .DONE

	; detect address char

	cmp [esi],byte '*'

	je .ADDR

	; detect a hex number

	cmp [esi],byte '$'

	je .HEX

	; detect a decimal number

	cmp [esi],byte '!'

	je .DEC

	; detect a binary number

	cmp [esi],byte '%'

	je .BIN

	; detect a decimal number

	cmp [esi],byte '0'

	jl .DEBUG_1

	cmp [esi],byte '9'

	jle .DEC_1

	; detect a symbol

	cmp [esi],byte 'A'

	jl .DEBUG_1

	cmp [esi],byte 'Z'

	jle .SYMB

	jmp .DEBUG_1

  .NEXT:

	inc esi

	jmp .READ

  .HEX:

	inc esi

	stdcall Get_Hex_Value

	jmp .DONE

  .DEC:

	inc esi

  .DEC_1:

	stdcall Get_Dec_Value

	jmp .DONE

  .BIN:

	inc esi

	stdcall Get_Bin_Value

	jmp .DONE

  .SYMB:

	stdcall Get_Symbol_Value

	jmp .DONE

  .ADDR:

	inc esi

	xor eax,eax

	mov ax,[Location_Counter]

	jmp .DONE

  .DEBUG_1:

	mov [Debug_Code],word 32

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Calc_Expression uses esi edx

  ; called only when processing the DFS, ADR, DBY, BYT or HBY pseudo ops

  ; compute the 1 or 2 byte value of an expression

  ; an expression can have 1 or 2 arguments

  ; if there are 2 arguments, they must be separated by a plus or minus

  ; return the result in AX

	lea esi,[bfExpression]

	xor eax,eax

	cmp [esi],byte 0

	je .DONE

	; first argument

	stdcall Calc_Operand_Value

	cmp eax,0xffffffff

	je .DONE

	cmp [esi],byte '+'

	je .PLUS

	cmp [esi],byte '-'

	je .MINUS

	jmp .DONE

  .PLUS:

	xor edx,edx

	mov dx,ax

	inc esi

	; second argument

	stdcall Calc_Operand_Value

	cmp eax,0xffffffff

	je .DONE

	add ax,dx

	jmp .DONE

  .MINUS:

	xor edx,edx

	mov dx,ax

	inc esi

	; second argument

	stdcall Calc_Operand_Value

	cmp eax,0xffffffff

	je .DONE

	sub dx,ax

	mov ax,dx

	jmp .DONE

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Get_Symbol_Value uses edi ecx

  ; read a symbol of up to 14 chars in length from ESI

  ; ESI is set outside of this proc

  ; symbols can only contain the chars: 0-9, A-Z and _

	lea edi,[bfSymbol]

	; ESI is already set to the first letter

	mov al,[esi]

	mov [edi],al

	inc esi

	inc edi

	mov ecx,1

  .COPY:

	; read the char from the input stream ESI

	; stop reading when a null, ), comma, plus or minus char is found

	mov al,[esi]

	cmp al,0

	je .LOOK_UP

	cmp al,'_'

	je .ADD

	cmp al,')'

	je .LOOK_UP

	cmp al,'+'

	je .LOOK_UP

	cmp al,'-'

	je .LOOK_UP

	cmp al,','

	je .LOOK_UP

	cmp al,'0'

	jl .ERROR

	cmp al,'9'

	jle .ADD

	cmp al,'A'

	jl .ERROR

	cmp al,'Z'

	jg .ERROR

  .ADD:

	; copy the char to bfSymbol

	mov [edi],al

	inc esi

	inc edi

	inc cx

	cmp cx,14

	jg .ERROR

	jmp .COPY

  .LOOK_UP:

	; find the symbol in the symbol table

	mov [edi],byte 0

	stdcall Lookup_Symbol

	jmp .DONE

  .ERROR:

	; could not find the symbol

	mov [Debug_Code],word 33

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Lookup_Symbol uses esi edi ecx

  ; lookup the current symbol and get it's value

  ; return the result in AX

	lea esi,[bfSymbol]

	lea edi,[Main_Memory]

	add edi,64512

	; check if there are any symbols

	cmp edi,[pSymbol_Table]

	je .NO_MATCH

	xor ecx,ecx

  .TEST:

	; test bfSymbol against the current entry in the symbol table

	mov al,[esi+ecx]

	cmp al,[edi+ecx]

	jne .NEXT

	cmp al,0

	je .MATCH

	inc cx

	cmp cx,14

	jl .TEST

  .NEXT:

	xor ecx,ecx

	; increment the symbol pointer

	add edi,16

	cmp edi,[pSymbol_Table]

	je .NO_MATCH

	jmp .TEST

  .MATCH:

	xor eax,eax

	mov ax,[edi+14]

	jmp .DONE

  .NO_MATCH:

	mov [Debug_Code],word 34

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Assemble_Instruction uses edi ecx

  ; instruction mnemonic is put into EAX as ASCII (lower 3 bytes)

  ; operand data is put into EDX - length in byte 4, mode in byte 3, 16 bit value in DX

	mov eax,dword [bfMnemonic]

	mov edx,dword [Operand_Data]

	; ================================================

	; # = immediate (low byte) - mode = 1

	; / = immediate (high byte) - mode = 2

	; zp,x and a,x - mode = 3

	; zp,y and a,y - mode = 4

	; (zp,x) - mode = 5

	; (zp),y - mode = 6

	; (a) - mode = 7

	; all other modes - mode = 0

	; ================================================

	lea edi,[Main_Memory]

	xor ecx,ecx

	mov cx,[Location_Counter]

	mov [Asm_Bytes],dword 0

	; is there anything in the mnemonic field ?

	cmp al,0

	je .DONE

	cmp al,'A'

	je .A

	cmp al,'B'

	je .B

	cmp al,'C'

	je .C

	cmp al,'D'

	je .D

	cmp al,'E'

	je .E

	cmp al,'I'

	je .I

	cmp al,'J'

	je .J

	cmp al,'L'

	je .L

	cmp al,'N'

	je .N

	cmp al,'O'

	je .O

	cmp al,'P'

	je .P

	cmp al,'R'

	je .R

	cmp al,'S'

	je .S

	cmp al,'T'

	je .T

	jmp .FAILED

  .A:

	shr eax,8

  .AND:

	cmp al,'N'

	jne .ADC

	shr eax,8

	cmp al,'D'

	jne .FAILED

	stdcall Assemble_AND

	cmp eax,0xffffffff

	je .ERROR_2

	jmp .DONE

  .ADC:

	cmp al,'D'

	jne .ASL

	shr eax,8

	cmp al,'C'

	jne .FAILED

	stdcall Assemble_ADC

	cmp eax,0xffffffff

	je .ERROR_2

	jmp .DONE

  .ASL:

	cmp al,'S'

	jne .FAILED

	shr eax,8

	cmp al,'L'

	jne .FAILED

	stdcall Assemble_ASL

	cmp eax,0xffffffff

	je .ERROR_2

	jmp .DONE

  .B:

	shr eax,8

  .BRK:

	cmp al,'R'

	jne .BCC

	shr eax,8

	cmp al,'K'

	jne .FAILED

	mov [edi+ecx],byte 0

	inc cx

	mov [Asm_Bytes],dword 0x01000000

	jmp .DONE

  .BCC:

	cmp al,'C'

	jne .BIT

	shr eax,8

	cmp al,'C'

	jne .BCS

	mov al,0x90

	stdcall Assemble_Branches

	jmp .DONE

  .BCS:

	cmp al,'S'

	jne .FAILED

	mov al,0xB0

	stdcall Assemble_Branches

	jmp .DONE

  .BIT:

	cmp al,'I'

	jne .BEQ

	shr eax,8

	cmp al,'T'

	jne .FAILED

	stdcall Assemble_BIT

	cmp eax,0xffffffff

	je .ERROR_2

	jmp .DONE

  .BEQ:

	cmp al,'E'

	jne .BMI

	shr eax,8

	cmp al,'Q'

	jne .FAILED

	mov al,0xF0

	stdcall Assemble_Branches

	jmp .DONE

  .BMI:

	cmp al,'M'

	jne .BNE

	shr eax,8

	cmp al,'I'

	jne .FAILED

	mov al,0x30

	stdcall Assemble_Branches

	jmp .DONE

  .BNE:

	cmp al,'N'

	jne .BPL

	shr eax,8

	cmp al,'E'

	jne .FAILED

	mov al,0xD0

	stdcall Assemble_Branches

	jmp .DONE

  .BPL:

	cmp al,'P'

	jne .BVC

	shr eax,8

	cmp al,'L'

	jne .FAILED

	mov al,0x10

	stdcall Assemble_Branches

	jmp .DONE

  .BVC:

	cmp al,'V'

	jne .FAILED

	shr eax,8

	cmp al,'C'

	jne .BVS

	mov al,0x50

	stdcall Assemble_Branches

	jmp .DONE

  .BVS:

	cmp al,'S'

	jne .FAILED

	mov al,0x70

	stdcall Assemble_Branches

	jmp .DONE

  .C:

	shr eax,8

  .CLC:

	cmp al,'L'

	jne .CMP

	shr eax,8

	cmp al,'C'

	jne .CLV

	mov [edi+ecx],byte 0x18

	inc cx

	mov [Asm_Bytes],dword 0x01000018

	jmp .DONE

  .CLV:

	cmp al,'V'

	jne .FAILED

	mov [edi+ecx],byte 0xB8

	inc cx

	mov [Asm_Bytes],dword 0x010000B8

	jmp .DONE

  .CMP:

	cmp al,'M'

	jne .CPX

	shr eax,8

	cmp al,'P'

	jne .FAILED

	stdcall Assemble_CMP

	cmp eax,0xffffffff

	je .ERROR_2

	jmp .DONE

  .CPX:

	cmp al,'P'

	jne .FAILED

	shr eax,8

	cmp al,'X'

	jne .CPY

	stdcall Assemble_CPX

	cmp eax,0xffffffff

	je .ERROR_2

	jmp .DONE

  .CPY:

	cmp al,'Y'

	jne .FAILED

	stdcall Assemble_CPY

	cmp eax,0xffffffff

	je .ERROR_2

	jmp .DONE

  .D:

	shr eax,8

  .DEC:

	cmp al,'E'

	jne .FAILED

	shr eax,8

	cmp al,'C'

	jne .DEX

	stdcall Assemble_DEC

	cmp eax,0xffffffff

	je .ERROR_2

	jmp .DONE

  .DEX:

	cmp al,'X'

	jne .DEY

	mov [edi+ecx],byte 0xCA

	inc cx

	mov [Asm_Bytes],dword 0x010000CA

	jmp .DONE

  .DEY:

	cmp al,'Y'

	jne .FAILED

	mov [edi+ecx],byte 0x88

	inc cx

	mov [Asm_Bytes],dword 0x01000088

	jmp .DONE

  .E:

	shr eax,8

  .EOR:

	cmp al,'O'

	jne .FAILED

	shr eax,8

	cmp al,'R'

	jne .FAILED

	stdcall Assemble_EOR

	cmp eax,0xffffffff

	je .ERROR_2

	jmp .DONE

  .I:

	shr eax,8

  .INC:

	cmp al,'N'

	jne .FAILED

	shr eax,8

	cmp al,'C'

	jne .INX

	stdcall Assemble_INC

	cmp eax,0xffffffff

	je .ERROR_2

	jmp .DONE

  .INX:

	cmp al,'X'

	jne .INY

	mov [edi+ecx],byte 0xE8

	inc cx

	mov [Asm_Bytes],dword 0x010000E8

	jmp .DONE

  .INY:

	cmp al,'Y'

	jne .FAILED

	mov [edi+ecx],byte 0xC8

	inc cx

	mov [Asm_Bytes],dword 0x010000C8

	jmp .DONE

  .J:

	shr eax,8

  .JMP:

	cmp al,'M'

	jne .JSR

	shr eax,8

	cmp al,'P'

	jne .FAILED

	stdcall Assemble_JMP

	cmp eax,0xffffffff

	je .ERROR_2

	jmp .DONE

  .JSR:

	cmp al,'S'

	jne .FAILED

	shr eax,8

	cmp al,'R'

	jne .FAILED

	mov [edi+ecx],byte 0x20

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov [edi+ecx],dh

	inc cx

	mov [Asm_Bytes],dword 0x03000020

	mov word [Asm_Bytes+1],dx

	shr edx,16

	cmp dl,0

	jne .ERROR_2

	jmp .DONE

  .L:

	shr eax,8

  .LDA:

	cmp al,'D'

	jne .LSR

	shr eax,8

	cmp al,'A'

	jne .LDX

	stdcall Assemble_LDA

	cmp eax,0xffffffff

	je .ERROR_2

	jmp .DONE

  .LDX:

	cmp al,'X'

	jne .LDY

	stdcall Assemble_LDX

	cmp eax,0xffffffff

	je .ERROR_2

	jmp .DONE

  .LDY:

	cmp al,'Y'

	jne .FAILED

	stdcall Assemble_LDY

	cmp eax,0xffffffff

	je .ERROR_2

	jmp .DONE

  .LSR:

	cmp al,'S'

	jne .FAILED

	shr eax,8

	cmp al,'R'

	jne .FAILED

	stdcall Assemble_LSR

	cmp eax,0xffffffff

	je .ERROR_2

	jmp .DONE

  .N:

	shr eax,8

  .NOP:

	cmp al,'O'

	jne .FAILED

	shr eax,8

	cmp al,'P'

	jne .FAILED

	mov [edi+ecx],byte 0xEA

	inc cx

	mov [Asm_Bytes],dword 0x010000EA

	jmp .DONE

  .O:

	shr eax,8

  .ORA:

	cmp al,'R'

	jne .FAILED

	shr eax,8

	cmp al,'A'

	jne .FAILED

	stdcall Assemble_ORA

	cmp eax,0xffffffff

	je .ERROR_2

	jmp .DONE

  .P:

	shr eax,8

  .PHA:

	cmp al,'H'

	jne .PLA

	shr eax,8

	cmp al,'A'

	jne .PHP

	mov [edi+ecx],byte 0x48

	inc cx

	mov [Asm_Bytes],dword 0x01000048

	jmp .DONE

  .PHP:

	cmp al,'P'

	jne .FAILED

	mov [edi+ecx],byte 0x08

	inc cx

	mov [Asm_Bytes],dword 0x01000008

	jmp .DONE

  .PLA:

	cmp al,'L'

	jne .FAILED

	shr eax,8

	cmp al,'A'

	jne .PLP

	mov [edi+ecx],byte 0x68

	inc cx

	mov [Asm_Bytes],dword 0x01000068

	jmp .DONE

  .PLP:

	cmp al,'P'

	jne .FAILED

	mov [edi+ecx],byte 0x28

	inc cx

	mov [Asm_Bytes],dword 0x01000028

	jmp .DONE

  .R:

	shr eax,8

  .ROL:

	cmp al,'O'

	jne .RTS

	shr eax,8

	cmp al,'L'

	jne .ROR

	stdcall Assemble_ROL

	cmp eax,0xffffffff

	je .ERROR_2

	jmp .DONE

  .ROR:

	cmp al,'R'

	jne .FAILED

	stdcall Assemble_ROR

	cmp eax,0xffffffff

	je .ERROR_2

	jmp .DONE

  .RTS:

	cmp al,'T'

	jne .FAILED

	mov [edi+ecx],byte 0x60

	inc cx

	mov [Asm_Bytes],dword 0x01000060

	jmp .DONE

  .S:

	shr eax,8

  .STA:

	cmp al,'T'

	jne .SBC

	shr eax,8

	cmp al,'A'

	jne .STX

	stdcall Assemble_STA

	cmp eax,0xffffffff

	je .ERROR_2

	jmp .DONE

  .STX:

	cmp al,'X'

	jne .STY

	stdcall Assemble_STX

	cmp eax,0xffffffff

	je .ERROR_2

	jmp .DONE

  .STY:

	cmp al,'Y'

	jne .FAILED

	stdcall Assemble_STY

	cmp eax,0xffffffff

	je .ERROR_2

	jmp .DONE

	jmp .DONE

  .SBC:

	cmp al,'B'

	jne .SEC

	shr eax,8

	cmp al,'C'

	jne .FAILED

	stdcall Assemble_SBC

	cmp eax,0xffffffff

	je .ERROR_2

	jmp .DONE

  .SEC:

	cmp al,'E'

	jne .FAILED

	shr eax,8

	cmp al,'C'

	jne .FAILED

	mov [edi+ecx],byte 0x38

	inc cx

	mov [Asm_Bytes],dword 0x01000038

	jmp .DONE

  .T:

	shr eax,8

  .TAX:

	cmp al,'A'

	jne .TSX

	shr eax,8

	cmp al,'X'

	jne .TAY

	mov [edi+ecx],byte 0xAA

	inc cx

	mov [Asm_Bytes],dword 0x010000AA

	jmp .DONE

  .TAY:

	cmp al,'Y'

	jne .FAILED

	mov [edi+ecx],byte 0xA8

	inc cx

	mov [Asm_Bytes],dword 0x010000A8

	jmp .DONE

  .TSX:

	cmp al,'S'

	jne .TXA

	shr eax,8

	cmp al,'X'

	jne .FAILED

	mov [edi+ecx],byte 0xBA

	inc cx

	mov [Asm_Bytes],dword 0x010000BA

	jmp .DONE

  .TXA:

	cmp al,'X'

	jne .TYA

	shr eax,8

	cmp al,'A'

	jne .TXS

	mov [edi+ecx],byte 0x8A

	inc cx

	mov [Asm_Bytes],dword 0x0100008A

	jmp .DONE

  .TXS:

	cmp al,'S'

	jne .FAILED

	mov [edi+ecx],byte 0x9A

	inc cx

	mov [Asm_Bytes],dword 0x0100009A

	jmp .DONE

  .TYA:

	cmp al,'Y'

	jne .FAILED

	shr eax,8

	cmp al,'A'

	jne .FAILED

	mov [edi+ecx],byte 0x98

	inc cx

	mov [Asm_Bytes],dword 0x01000098

	jmp .DONE

  .FAILED:

	; unknown mnemonic

	mov [Debug_Code],word 35

	mov eax,0xffffffff

	jmp .DONE

  .ERROR_2:

	; invalid addressing mode

	mov [Debug_Code],word 37

  .DONE:

	mov [Location_Counter],cx

	ret

endp

; -------------------------------------------------------------------------------------

proc Assemble_ADC

	; assemble the ADC instruction

	xor eax,eax

	; is the length of the operand zero ?

	bswap edx

	cmp dl,0

	je .ERROR

	; put the mode into AL

	mov al,dh

	bswap edx

	; the operand data is in DX

	mov word [Asm_Bytes+1],dx

  .IMMED_LO:

	; immediate (low byte) - mode = 1

	cmp al,1

	jne .IMMED_HI

	mov [edi+ecx],byte 0x69

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x69

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .IMMED_HI:

	; immediate (high byte) - mode = 2

	cmp al,2

	jne .ZPAX

	mov [edi+ecx],byte 0x69

	inc cx

	mov [edi+ecx],dh

	inc cx

	mov byte [Asm_Bytes],0x69

	mov byte [Asm_Bytes+1],dh

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZPAX:

	; a,x - mode = 3

	cmp al,3

	jne .AY

	cmp dh,0

	je .ZPX

	mov [edi+ecx],byte 0x7D

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x7D

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ZPX:

	; zp,x - mode = 3

	mov [edi+ecx],byte 0x75

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x75

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .AY:

	; a,y - mode = 4

	cmp al,4

	jne .ZPIX

	mov [edi+ecx],byte 0x79

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x79

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ZPIX:

	; (zp,x) - mode = 5

	cmp al,5

	jne .ZPIY

	mov [edi+ecx],byte 0x61

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x61

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZPIY:

	; (zp),y - mode  = 6

	cmp al,6

	jne .ZP

	mov [edi+ecx],byte 0x71

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x71

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZP:

	; zp - mode = 0

	cmp al,0

	jne .ERROR

	cmp dh,0

	jne .ABS

	mov [edi+ecx],byte 0x65

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x65

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ABS:

	; a - mode = 0

	mov [edi+ecx],byte 0x6D

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x6D

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Assemble_SBC

	; assemble the SBC instruction

	xor eax,eax

	; is the length of the operand zero ?

	bswap edx

	cmp dl,0

	je .ERROR

	; put the mode into AL

	mov al,dh

	bswap edx

	; the operand data is in DX

	mov word [Asm_Bytes+1],dx

  .IMMED_LO:

	; immediate (low byte) - mode = 1

	cmp al,1

	jne .IMMED_HI

	mov [edi+ecx],byte 0xE9

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xE9

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .IMMED_HI:

	; immediate (high byte) - mode = 2

	cmp al,2

	jne .ZPAX

	mov [edi+ecx],byte 0xE9

	inc cx

	mov [edi+ecx],dh

	inc cx

	mov byte [Asm_Bytes],0xE9

	mov byte [Asm_Bytes+1],dh

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZPAX:

	; a,x - mode = 3

	cmp al,3

	jne .AY

	cmp dh,0

	je .ZPX

	mov [edi+ecx],byte 0xFD

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0xFD

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ZPX:

	; zp,x - mode = 3

	mov [edi+ecx],byte 0xF5

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xF5

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .AY:

	; a,y - mode = 4

	cmp al,4

	jne .ZPIX

	mov [edi+ecx],byte 0xF9

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0xF9

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ZPIX:

	; (zp,x) - mode = 5

	cmp al,5

	jne .ZPIY

	mov [edi+ecx],byte 0xE1

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xE1

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZPIY:

	; (zp),y - mode = 6

	cmp al,6

	jne .ZP

	mov [edi+ecx],byte 0xF1

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xF1

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZP:

	; zp - mode = 0

	cmp al,0

	jne .ERROR

	cmp dh,0

	jne .ABS

	mov [edi+ecx],byte 0xE5

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xE5

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ABS:

	; a - mode = 0

	mov [edi+ecx],byte 0xED

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0xED

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Assemble_AND

	; assemble the AND instruction

	xor eax,eax

	; is the length of the operand zero ?

	bswap edx

	cmp dl,0

	je .ERROR

	; put the mode into AL

	mov al,dh

	bswap edx

	; the operand data is in DX

	mov word [Asm_Bytes+1],dx

  .IMMED_LO:

	; immediate (low byte) - mode = 1

	cmp al,1

	jne .IMMED_HI

	mov [edi+ecx],byte 0x29

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x29

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .IMMED_HI:

	; immediate (high byte) - mode = 2

	cmp al,2

	jne .ZPAX

	mov [edi+ecx],byte 0x29

	inc cx

	mov [edi+ecx],dh

	inc cx

	mov byte [Asm_Bytes],0x29

	mov byte [Asm_Bytes+1],dh

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZPAX:

	; a,x - mode = 3

	cmp al,3

	jne .AY

	cmp dh,0

	je .ZPX

	mov [edi+ecx],byte 0x3D

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x3D

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ZPX:

	; zp,x - mode = 3

	mov [edi+ecx],byte 0x35

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x35

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .AY:

	; a,y - mode = 4

	cmp al,4

	jne .ZPIX

	mov [edi+ecx],byte 0x39

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x39

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ZPIX:

	; (zp,x) - mode = 5

	cmp al,5

	jne .ZPIY

	mov [edi+ecx],byte 0x21

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x21

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZPIY:

	; (zp),y - mode = 6

	cmp al,6

	jne .ZP

	mov [edi+ecx],byte 0x31

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x31

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZP:

	; zp - mode = 0

	cmp al,0

	jne .ERROR

	cmp dh,0

	jne .ABS

	mov [edi+ecx],byte 0x25

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x25

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ABS:

	; a - mode = 0

	mov [edi+ecx],byte 0x2D

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x2D

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Assemble_ORA

	; assemble the ORA instruction

	xor eax,eax

	; is the length of the operand zero ?

	bswap edx

	cmp dl,0

	je .ERROR

	; put the mode into AL

	mov al,dh

	bswap edx

	; the operand data is in DX

	mov word [Asm_Bytes+1],dx

  .IMMED_LO:

	; immediate (low byte) - mode = 1

	cmp al,1

	jne .IMMED_HI

	mov [edi+ecx],byte 0x09

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x09

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .IMMED_HI:

	; immediate (high byte) - mode = 2

	cmp al,2

	jne .ZPAX

	mov [edi+ecx],byte 0x09

	inc cx

	mov [edi+ecx],dh

	inc cx

	mov byte [Asm_Bytes],0x09

	mov byte [Asm_Bytes+1],dh

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZPAX:

	; a,x - mode = 3

	cmp al,3

	jne .AY

	cmp dh,0

	je .ZPX

	mov [edi+ecx],byte 0x1D

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x1D

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ZPX:

	; zp,x - mode = 3

	mov [edi+ecx],byte 0x15

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x15

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .AY:

	; a,y - mode = 4

	cmp al,4

	jne .ZPIX

	mov [edi+ecx],byte 0x19

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x19

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ZPIX:

	; (zp,x) - mode = 5

	cmp al,5

	jne .ZPIY

	mov [edi+ecx],byte 0x01

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x01

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZPIY:

	; (zp),y - mode  = 6

	cmp al,6

	jne .ZP

	mov [edi+ecx],byte 0x11

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x11

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZP:

	; zp - mode = 0

	cmp al,0

	jne .ERROR

	cmp dh,0

	jne .ABS

	mov [edi+ecx],byte 0x05

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x05

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ABS:

	; a - mode = 0

	mov [edi+ecx],byte 0x0D

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x0D

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Assemble_EOR

	; assemble the EOR instruction

	xor eax,eax

	; is the length of the operand zero ?

	bswap edx

	cmp dl,0

	je .ERROR

	; put the mode into AL

	mov al,dh

	bswap edx

	; the operand data is in DX

	mov word [Asm_Bytes+1],dx

  .IMMED_LO:

	; immediate (low byte) - mode = 1

	cmp al,1

	jne .IMMED_HI

	mov [edi+ecx],byte 0x49

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x49

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .IMMED_HI:

	; immediate (high byte) - mode = 2

	cmp al,2

	jne .ZPAX

	mov [edi+ecx],byte 0x49

	inc cx

	mov [edi+ecx],dh

	inc cx

	mov byte [Asm_Bytes],0x49

	mov byte [Asm_Bytes+1],dh

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZPAX:

	; a,x - mode = 3

	cmp al,3

	jne .AY

	cmp dh,0

	je .ZPX

	mov [edi+ecx],byte 0x5D

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x5D

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ZPX:

	; zp,x - mode = 3

	mov [edi+ecx],byte 0x55

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x55

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .AY:

	; a,y - mode = 4

	cmp al,4

	jne .ZPIX

	mov [edi+ecx],byte 0x59

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x59

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ZPIX:

	; (zp,x) - mode = 5

	cmp al,5

	jne .ZPIY

	mov [edi+ecx],byte 0x41

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x41

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZPIY:

	; (zp),y - mode  = 6

	cmp al,6

	jne .ZP

	mov [edi+ecx],byte 0x51

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x51

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZP:

	; zp - mode = 0

	cmp al,0

	jne .ERROR

	cmp dh,0

	jne .ABS

	mov [edi+ecx],byte 0x45

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x45

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ABS:

	; a - mode = 0

	mov [edi+ecx],byte 0x4D

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x4D

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Assemble_LDA

	; assemble the LDA instruction

	xor eax,eax

	; is the length of the operand zero ?

	bswap edx

	cmp dl,0

	je .ERROR

	; put the mode into AL

	mov al,dh

	bswap edx

	; the operand data is in DX

	mov word [Asm_Bytes+1],dx

  .IMMED_LO:

	; immediate (low byte) - mode = 1

	cmp al,1

	jne .IMMED_HI

	mov [edi+ecx],byte 0xA9

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xA9

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .IMMED_HI:

	; immediate (high byte) - mode = 2

	cmp al,2

	jne .ZPAX

	mov [edi+ecx],byte 0xA9

	inc cx

	mov [edi+ecx],dh

	inc cx

	mov byte [Asm_Bytes],0xA9

	mov byte [Asm_Bytes+1],dh

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZPAX:

	; a,x - mode = 3

	cmp al,3

	jne .AY

	cmp dh,0

	je .ZPX

	mov [edi+ecx],byte 0xBD

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0xBD

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ZPX:

	; zp,x - mode = 3

	mov [edi+ecx],byte 0xB5

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xB5

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .AY:

	; a,y - mode = 4

	cmp al,4

	jne .ZPIX

	mov [edi+ecx],byte 0xB9

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0xB9

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ZPIX:

	; (zp,x) - mode = 5

	cmp al,5

	jne .ZPIY

	mov [edi+ecx],byte 0xA1

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xA1

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZPIY:

	; (zp),y - mode = 6

	cmp al,6

	jne .ZP

	mov [edi+ecx],byte 0xB1

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xB1

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZP:

	; zp - mode = 0

	cmp al,0

	jne .ERROR

	cmp dh,0

	jne .ABS

	mov [edi+ecx],byte 0xA5

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xA5

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ABS:

	; a - mode = 0

	mov [edi+ecx],byte 0xAD

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0xAD

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Assemble_STA

	; assemble the STA instruction

	xor eax,eax

	; is the length of the operand zero ?

	bswap edx

	cmp dl,0

	je .ERROR

	; put the mode into AL

	mov al,dh

	bswap edx

	; the operand data is in DX

	mov word [Asm_Bytes+1],dx

  .ZPAX:

	; a,x - mode = 3

	cmp al,3

	jne .AY

	cmp dh,0

	je .ZPX

	mov [edi+ecx],byte 0x9D

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x9D

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ZPX:

	; zp,x - mode = 3

	mov [edi+ecx],byte 0x95

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x95

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .AY:

	; a,y - mode = 4

	cmp al,4

	jne .ZPIX

	mov [edi+ecx],byte 0x99

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x99

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ZPIX:

	; (zp,x) - mode = 5

	cmp al,5

	jne .ZPIY

	mov [edi+ecx],byte 0x81

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x81

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZPIY:

	; (zp),y - mode = 6

	cmp al,6

	jne .ZP

	mov [edi+ecx],byte 0x91

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x91

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZP:

	; zp - mode = 0

	cmp al,0

	jne .ERROR

	cmp dh,0

	jne .ABS

	mov [edi+ecx],byte 0x85

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x85

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ABS:

	; a - mode = 0

	mov [edi+ecx],byte 0x8D

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x8D

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Assemble_LDX

	; assemble the LDX instruction

	xor eax,eax

	; is the length of the operand zero ?

	bswap edx

	cmp dl,0

	je .ERROR

	; put the mode into AL

	mov al,dh

	bswap edx

	; the operand data is in DX

	mov word [Asm_Bytes+1],dx

  .IMMED_LO:

	; immediate (low byte) - mode = 1

	cmp al,1

	jne .IMMED_HI

	mov [edi+ecx],byte 0xA2

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xA2

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .IMMED_HI:

	; immediate (high byte) - mode = 2

	cmp al,2

	jne .ZPY

	mov [edi+ecx],byte 0xA2

	inc cx

	mov [edi+ecx],dh

	inc cx

	mov byte [Asm_Bytes],0xA2

	mov byte [Asm_Bytes+1],dh

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZPY:

	; zp,y - mode = 4

	cmp al,4

	jne .ZP

	cmp dh,0

	jne .AY

	mov [edi+ecx],byte 0xB6

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xB6

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .AY:

	; a,y - mode = 4

	mov [edi+ecx],byte 0xBE

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0xBE

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ZP:

	; zp - mode = 0

	cmp al,0

	jne .ERROR

	cmp dh,0

	jne .ABS

	mov [edi+ecx],byte 0xA6

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xA6

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ABS:

	; a - mode = 0

	mov [edi+ecx],byte 0xAE

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0xAE

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Assemble_STX

	; assemble the STX instruction

	xor eax,eax

	; is the length of the operand zero ?

	bswap edx

	cmp dl,0

	je .ERROR

	; put the mode into AL

	mov al,dh

	bswap edx

	; the operand data is in DX

	mov word [Asm_Bytes+1],dx

  .ZPY:

	; zp,y - mode = 4

	cmp al,4

	jne .ZP

	mov [edi+ecx],byte 0x96

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x96

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZP:

	; zp - mode = 0

	cmp al,0

	jne .ERROR

	cmp dh,0

	jne .ABS

	mov [edi+ecx],byte 0x86

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x86

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ABS:

	; a - mode = 0

	mov [edi+ecx],byte 0x8E

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x8E

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Assemble_LDY

	; assemble the LDY instruction

	xor eax,eax

	; is the length of the operand zero ?

	bswap edx

	cmp dl,0

	je .ERROR

	; put the mode into AL

	mov al,dh

	bswap edx

	; the operand data is in DX

	mov word [Asm_Bytes+1],dx

  .IMMED_LO:

	; immediate (low byte) - mode = 1

	cmp al,1

	jne .IMMED_HI

	mov [edi+ecx],byte 0xA0

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xA0

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .IMMED_HI:

	; immediate (high byte) - mode = 2

	cmp al,2

	jne .ZPX

	mov [edi+ecx],byte 0xA0

	inc cx

	mov [edi+ecx],dh

	inc cx

	mov byte [Asm_Bytes],0xA0

	mov byte [Asm_Bytes+1],dh

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZPX:

	; zp,x - mode = 3

	cmp al,3

	jne .ZP

	cmp dh,0

	jne .AX

	mov [edi+ecx],byte 0xB4

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xB4

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .AX:

	; a,x - mode = 3

	mov [edi+ecx],byte 0xBC

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0xBC

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ZP:

	; zp - mode = 0

	cmp al,0

	jne .ERROR

	cmp dh,0

	jne .ABS

	mov [edi+ecx],byte 0xA4

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xA4

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ABS:

	; a - mode = 0

	mov [edi+ecx],byte 0xAC

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0xAC

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Assemble_STY

	; assemble the STY instruction

	xor eax,eax

	; is the length of the operand zero ?

	bswap edx

	cmp dl,0

	je .ERROR

	; put the mode into AL

	mov al,dh

	bswap edx

	; the operand data is in DX

	mov word [Asm_Bytes+1],dx

  .ZPX:

	; zp,x - mode = 3

	cmp al,3

	jne .ZP

	mov [edi+ecx],byte 0x94

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x94

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZP:

	; zp - mode = 0

	cmp al,0

	jne .ERROR

	cmp dh,0

	jne .ABS

	mov [edi+ecx],byte 0x84

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x84

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ABS:

	; a - mode = 0

	mov [edi+ecx],byte 0x8C

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x8C

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Assemble_INC

	; assemble the INC instruction

	xor eax,eax

	; is the length of the operand zero ?

	bswap edx

	cmp dl,0

	je .ERROR

	; put the mode into AL

	mov al,dh

	bswap edx

	; the operand data is in DX

	mov word [Asm_Bytes+1],dx

  .ZPX:

	; zp,x - mode = 3

	cmp al,3

	jne .ZP

	cmp dh,0

	jne .AX

	mov [edi+ecx],byte 0xF6

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xF6

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .AX:

	; a,x - mode = 3

	mov [edi+ecx],byte 0xFE

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0xFE

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ZP:

	; zp - mode = 0

	cmp al,0

	jne .ERROR

	cmp dh,0

	jne .ABS

	mov [edi+ecx],byte 0xE6

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xE6

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ABS:

	; a - mode = 0

	mov [edi+ecx],byte 0xEE

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0xEE

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Assemble_DEC

	; assemble the DEC instruction

	xor eax,eax

	; is the length of the operand zero ?

	bswap edx

	cmp dl,0

	je .ERROR

	; put the mode into AL

	mov al,dh

	bswap edx

	; the operand data is in DX

	mov word [Asm_Bytes+1],dx

  .ZPX:

	; zp,x - mode = 3

	cmp al,3

	jne .ZP

	cmp dh,0

	jne .AX

	mov [edi+ecx],byte 0xD6

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xD6

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .AX:

	; a,x - mode = 3

	mov [edi+ecx],byte 0xDE

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0xDE

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ZP:

	; zp - mode = 0

	cmp al,0

	jne .ERROR

	cmp dh,0

	jne .ABS

	mov [edi+ecx],byte 0xC6

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xC6

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ABS:

	; a - mode = 0

	mov [edi+ecx],byte 0xCE

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0xCE

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Assemble_CMP

	; assemble the CMP instruction

	xor eax,eax

	; is the length of the operand zero ?

	bswap edx

	cmp dl,0

	je .ERROR

	; put the mode into AL

	mov al,dh

	bswap edx

	; the operand data is in DX

	mov word [Asm_Bytes+1],dx

  .IMMED_LO:

	; immediate (low byte) - mode = 1

	cmp al,1

	jne .IMMED_HI

	mov [edi+ecx],byte 0xC9

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xC9

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .IMMED_HI:

	; immediate (high byte) - mode = 2

	cmp al,2

	jne .ZPX

	mov [edi+ecx],byte 0xC9

	inc cx

	mov [edi+ecx],dh

	inc cx

	mov byte [Asm_Bytes],0xC9

	mov byte [Asm_Bytes+1],dh

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZPX:

	; zp,x - mode = 3

	cmp al,3

	jne .AY

	cmp dh,0

	jne .AX

	mov [edi+ecx],byte 0xD5

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xD5

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .AX:

	; a,x - mode = 3

	mov [edi+ecx],byte 0xDD

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0xDD

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .AY:

	; a,y - mode = 4

	cmp al,4

	jne .ZPIX

	mov [edi+ecx],byte 0xD9

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0xD9

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ZPIX:

	; (zp,x) - mode = 5

	cmp al,5

	jne .ZPIY

	mov [edi+ecx],byte 0xC1

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xC1

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZPIY:

	; (zp),y - mode = 6

	cmp al,6

	jne .ZP

	mov [edi+ecx],byte 0xD1

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xD1

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZP:

	; zp - mode = 0

	cmp al,0

	jne .ERROR

	cmp dh,0

	jne .ABS

	mov [edi+ecx],byte 0xC5

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xC5

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ABS:

	; a - mode = 0

	mov [edi+ecx],byte 0xCD

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0xCD

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Assemble_CPX

	; assemble the CPX instruction

	xor eax,eax

	; is the length of the operand zero ?

	bswap edx

	cmp dl,0

	je .ERROR

	; put the mode into AL

	mov al,dh

	bswap edx

	; the operand data is in DX

	mov word [Asm_Bytes+1],dx

  .IMMED_LO:

	; immediate (low byte) - mode = 1

	cmp al,1

	jne .IMMED_HI

	mov [edi+ecx],byte 0xE0

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xE0

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .IMMED_HI:

	; immediate (high byte) - mode = 2

	cmp al,2

	jne .ZP

	mov [edi+ecx],byte 0xE0

	inc cx

	mov [edi+ecx],dh

	inc cx

	mov byte [Asm_Bytes],0xE0

	mov byte [Asm_Bytes+1],dh

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZP:

	; zp - mode = 0

	cmp al,0

	jne .ERROR

	cmp dh,0

	jne .ABS

	mov [edi+ecx],byte 0xE4

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xE4

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ABS:

	; a - mode = 0

	mov [edi+ecx],byte 0xEC

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0xEC

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Assemble_CPY

	; assemble the CPY instruction

	xor eax,eax

	; is the length of the operand zero ?

	bswap edx

	cmp dl,0

	je .ERROR

	; put the mode into AL

	mov al,dh

	bswap edx

	; the operand data is in DX

	mov word [Asm_Bytes+1],dx

  .IMMED_LO:

	; immediate (low byte) - mode = 1

	cmp al,1

	jne .IMMED_HI

	mov [edi+ecx],byte 0xC0

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xC0

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .IMMED_HI:

	; immediate (high byte) - mode = 2

	cmp al,2

	jne .ZP

	mov [edi+ecx],byte 0xC0

	inc cx

	mov [edi+ecx],dh

	inc cx

	mov byte [Asm_Bytes],0xC0

	mov byte [Asm_Bytes+1],dh

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ZP:

	; zp - mode = 0

	cmp al,0

	jne .ERROR

	cmp dh,0

	jne .ABS

	mov [edi+ecx],byte 0xC4

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0xC4

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ABS:

	; a - mode = 0

	mov [edi+ecx],byte 0xCC

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0xCC

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Assemble_BIT

	; assemble the BIT instruction

	xor eax,eax

	; is the length of the operand zero ?

	bswap edx

	cmp dl,0

	je .ERROR

	; put the mode into AL

	mov al,dh

	bswap edx

	; the operand data is in DX

	mov word [Asm_Bytes+1],dx

  .ZP:

	; zp - mode = 0

	cmp al,0

	jne .ERROR

	cmp dh,0

	jne .ABS

	mov [edi+ecx],byte 0x24

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x24

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ABS:

	; a - mode = 0

	mov [edi+ecx],byte 0x2C

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x2C

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Assemble_ASL

	; assemble the ASL instruction

	xor eax,eax

	bswap edx

	; put the mode into AL

	mov al,dh

	; is the length of the operand zero ?

	cmp dl,0

	je .ACC

	bswap edx

	; the operand data is in DX

	mov word [Asm_Bytes+1],dx

  .ZPX:

	; zp,x - mode = 3

	cmp al,3

	jne .ZP

	cmp dh,0

	jne .AX

	mov [edi+ecx],byte 0x16

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x16

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .AX:

	; a,x - mode = 3

	mov [edi+ecx],byte 0x1E

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x1E

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ZP:

	; zp - mode = 0

	cmp al,0

	jne .ERROR

	cmp dh,0

	jne .ABS

	mov [edi+ecx],byte 0x06

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x06

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ABS:

	; a - mode = 0

	mov [edi+ecx],byte 0x0E

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x0E

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ACC:

	; accumulator mode

	cmp al,0

	jne .ERROR

	mov [edi+ecx],byte 0x0A

	inc cx

	mov byte [Asm_Bytes],0x0A

	mov byte [Asm_Bytes+3],1

	jmp .DONE

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Assemble_LSR

	; assemble the LSR instruction

	xor eax,eax

	bswap edx

	; put the mode into AL

	mov al,dh

	; is the length of the operand zero ?

	cmp dl,0

	je .ACC

	bswap edx

	; the operand data is in DX

	mov word [Asm_Bytes+1],dx

  .ZPX:

	; zp,x - mode = 3

	cmp al,3

	jne .ZP

	cmp dh,0

	jne .AX

	mov [edi+ecx],byte 0x56

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x56

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .AX:

	; a,x - mode = 3

	mov [edi+ecx],byte 0x5E

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x5E

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ZP:

	; zp - mode = 0

	cmp al,0

	jne .ERROR

	cmp dh,0

	jne .ABS

	mov [edi+ecx],byte 0x46

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x46

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ABS:

	; a - mode = 0

	mov [edi+ecx],byte 0x4E

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x4E

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ACC:

	; accumulator mode

	cmp al,0

	jne .ERROR

	mov [edi+ecx],byte 0x4A

	inc cx

	mov byte [Asm_Bytes],0x4A

	mov byte [Asm_Bytes+3],1

	jmp .DONE

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Assemble_ROL

	; assemble the ROL instruction

	xor eax,eax

	bswap edx

	; put the mode into AL

	mov al,dh

	; is the length of the operand zero ?

	cmp dl,0

	je .ACC

	bswap edx

	; the operand data is in DX

	mov word [Asm_Bytes+1],dx

  .ZPX:

	; zp,x - mode = 3

	cmp al,3

	jne .ZP

	cmp dh,0

	jne .AX

	mov [edi+ecx],byte 0x36

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x36

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .AX:

	; a,x - mode = 3

	mov [edi+ecx],byte 0x3E

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x3E

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ZP:

	; zp - mode = 0

	cmp al,0

	jne .ERROR

	cmp dh,0

	jne .ABS

	mov [edi+ecx],byte 0x26

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x26

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ABS:

	; a - mode = 0

	mov [edi+ecx],byte 0x2E

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x2E

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ACC:

	; accumulator mode

	cmp al,0

	jne .ERROR

	mov [edi+ecx],byte 0x2A

	inc cx

	mov byte [Asm_Bytes],0x2A

	mov byte [Asm_Bytes+3],1

	jmp .DONE

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Assemble_ROR

	; assemble the ROR instruction

	xor eax,eax

	bswap edx

	; put the mode into AL

	mov al,dh

	; is the length of the operand zero ?

	cmp dl,0

	je .ACC

	bswap edx

	; the operand data is in DX

	mov word [Asm_Bytes+1],dx

  .ZPX:

	; zp,x - mode = 3

	cmp al,3

	jne .ZP

	cmp dh,0

	jne .AX

	mov [edi+ecx],byte 0x76

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x76

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .AX:

	; a,x - mode = 3

	mov [edi+ecx],byte 0x7E

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x7E

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ZP:

	; zp - mode = 0

	cmp al,0

	jne .ERROR

	cmp dh,0

	jne .ABS

	mov [edi+ecx],byte 0x66

	inc cx

	mov [edi+ecx],dl

	inc cx

	mov byte [Asm_Bytes],0x66

	mov byte [Asm_Bytes+3],2

	jmp .DONE

  .ABS:

	; a - mode = 0

	mov [edi+ecx],byte 0x6E

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x6E

	mov byte [Asm_Bytes+3],3

	jmp .DONE

  .ACC:

	; accumulator mode

	cmp al,0

	jne .ERROR

	mov [edi+ecx],byte 0x6A

	inc cx

	mov byte [Asm_Bytes],0x6A

	mov byte [Asm_Bytes+3],1

	jmp .DONE

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Assemble_JMP

	; assemble the JMP instruction

	xor eax,eax

	; is the length of the operand zero ?

	bswap edx

	cmp dl,0

	je .ERROR

	; put the mode into AL

	mov al,dh

	bswap edx

	; the operand data is in DX

	mov word [Asm_Bytes+1],dx

	mov byte [Asm_Bytes+3],3

  .ABS:

	; a - mode = 0

	cmp al,0

	jne .IND

	mov [edi+ecx],byte 0x4C

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x4C

	jmp .DONE

  .IND:

	; (a) - mode = 7

	cmp al,7

	jne .ERROR

	mov [edi+ecx],byte 0x6C

	inc cx

	mov [edi+ecx],dx

	add cx,2

	mov byte [Asm_Bytes],0x6C

	jmp .DONE

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Assemble_Branches

  ; assemble the branch instructions

  ; BPL, BMI, BVC, BVS, BCC, BCS, BNE, BEQ

  ; the op code is passed in AL

	; is the length of the operand zero ?

	bswap edx

	cmp dl,0

	je .ERROR

	; check the mode

	cmp dh,0

	jne .ERROR

	bswap edx

	; the operand data is in DX

	mov byte [Asm_Bytes],al

	mov byte [Asm_Bytes+3],2

	; calculate the relative offset

	sub dx,2

	sub dx,cx

	; check for out of range errors:

  .LT:

	; for DX > CX

	; (i) DH != 0

	; (ii) DH = 0 and DL = 80

	cmp dh,0

	jne .GT

	cmp dl,0x80

	je .ERROR

	jmp .OP

  .GT:

	; for DX < CX

	; (i) DH != FF

	; (ii) DH = FF and DL < 80

	cmp dh,0xff

	jne .ERROR

	cmp dl,0x80

	jb .ERROR

  .OP:

	; write the op code

	mov [edi+ecx],al

	inc cx

	; write the relative offset

	mov [edi+ecx],dl

	inc cx

	xor eax,eax

	mov byte [Asm_Bytes+1],dl

	jmp .DONE

  .ERROR:

	mov [Debug_Code],word 36

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

macro GET_BYTE_IMMED
{
  ; the op code byte has just been read - increment the program counter (CX)

  inc cx

  ; read the data byte

  mov al,[esi+ecx]

  ; increment CX to the next instruction

  inc cx
}

; -------------------------------------------------------------------------------------

macro GET_BYTE_ABS
{
  ; the op code byte has just been read - increment the program counter (CX)

  inc cx

  xor edx,edx

  ; read the address of the data into DX

  mov dx,[esi+ecx]

  mov word [Exe_Info_67],dx

  ; increment CX to the next instruction

  add cx,2

  ; read the data byte

  mov al,[esi+edx] 
}

; -------------------------------------------------------------------------------------

macro GET_BYTE_ZP
{
  ; the op code byte has just been read - increment the program counter (CX)

  inc cx

  xor edx,edx

  ; read the ZP address of the data into DL

  mov dl,[esi+ecx]

  mov word [Exe_Info_67],dx

  ; increment CX to the next instruction

  inc cx

  ; read the data byte

  mov al,[esi+edx]
}

; -------------------------------------------------------------------------------------

macro GET_BYTE_AX
{
  ; the op code byte has just been read - increment the program counter (CX)

  inc cx

  xor edx,edx

  ; read the address of the data into DX

  mov dx,[esi+ecx]

  ; increment CX to the next instruction

  add cx,2

  ; index the address of the data by the value of the X register

  add dl,[Index_Reg_X]

  adc dh,0

  mov word [Exe_Info_67],dx

  ; read the data byte

  mov al,[esi+edx]
}

; -------------------------------------------------------------------------------------

macro GET_BYTE_AY
{
  ; the op code byte has just been read - increment the program counter (CX)

  inc cx

  xor edx,edx

  ; read the address of the data into DX

  mov dx,[esi+ecx]

  ; increment CX to the next instruction

  add cx,2

  ; index the address of the data by the value of the Y register

  add dl,[Index_Reg_Y]

  adc dh,0

  mov word [Exe_Info_67],dx

  ; read the data byte

  mov al,[esi+edx] 
}

; -------------------------------------------------------------------------------------

macro GET_BYTE_ZPX
{
  ; the op code byte has just been read - increment the program counter (CX)

  inc cx

  xor edx,edx

  ; read the ZP address of the data into DL

  mov dl,[esi+ecx]

  ; increment CX to the next instruction

  inc cx

  ; index the address of the data by the value of the X register

  add dl,[Index_Reg_X]

  mov word [Exe_Info_67],dx

  ; read the data byte

  mov al,[esi+edx] 
}

; -------------------------------------------------------------------------------------

macro GET_BYTE_ZPY
{
  ; the op code byte has just been read - increment the program counter (CX)

  inc cx

  xor edx,edx

  ; read the ZP address of the data into DL

  mov dl,[esi+ecx]

  ; increment CX to the next instruction

  inc cx

  ; index the address of the data by the value of the Y register

  add dl,[Index_Reg_Y]

  mov word [Exe_Info_67],dx

  ; read the data byte

  mov al,[esi+edx]
}

; -------------------------------------------------------------------------------------

macro GET_BYTE_ZPIX
{
  ; the op code byte has just been read - increment the program counter (CX)

  inc cx

  xor edx,edx

  ; get the byte that stores the zero page address

  mov dl,[esi+ecx]

  ; increment CX to the next instruction

  inc cx

  ; add X to the zero page address (result wraps to a zero page address)

  add dl,[Index_Reg_X]

  ; read the 2 byte target address stored at the zero page address

  mov dx,[esi+edx]

  mov word [Exe_Info_67],dx

  ; read the data byte

  mov al,[esi+edx] 
}

; -------------------------------------------------------------------------------------

macro GET_BYTE_ZPIY
{
  ; the op code byte has just been read - increment the program counter (CX)

  inc cx

  xor edx,edx

  ; get the byte that stores the zero page address of the target address

  mov dl,[esi+ecx]

  ; increment CX to the next instruction

  inc cx

  ; read the 2 byte target address stored at the zero page address

  mov dx,[esi+edx]

  ; add Y to the target address

  add dl,[Index_Reg_Y]

  adc dh,0

  mov word [Exe_Info_67],dx

  ; read the data byte

  mov al,[esi+edx]
}

; -------------------------------------------------------------------------------------

proc Execute_Instruction

  ; execute the instruction

	stdcall Reset_Exe_Info

	mov word [Exe_Info],cx

	; the op code byte is passed in AL

	cmp al,0

	je .DONE

	cmp al,0x69

	je .ADC_69

	cmp al,0x6D

	je .ADC_6D

	cmp al,0x65

	je .ADC_65

	cmp al,0x7D

	je .ADC_7D

	cmp al,0x79

	je .ADC_79

	cmp al,0x75

	je .ADC_75

	cmp al,0x61

	je .ADC_61

	cmp al,0x71

	je .ADC_71

	cmp al,0xE9

	je .SBC_E9

	cmp al,0xED

	je .SBC_ED

	cmp al,0xE5

	je .SBC_E5

	cmp al,0xFD

	je .SBC_FD

	cmp al,0xF9

	je .SBC_F9

	cmp al,0xF5

	je .SBC_F5

	cmp al,0xE1

	je .SBC_E1

	cmp al,0xF1

	je .SBC_F1

	cmp al,0x29

	je .AND_29

	cmp al,0x2D

	je .AND_2D

	cmp al,0x25

	je .AND_25

	cmp al,0x3D

	je .AND_3D

	cmp al,0x39

	je .AND_39

	cmp al,0x35

	je .AND_35

	cmp al,0x21

	je .AND_21

	cmp al,0x31

	je .AND_31

	cmp al,0x09

	je .ORA_09

	cmp al,0x0D

	je .ORA_0D

	cmp al,0x05

	je .ORA_05

	cmp al,0x1D

	je .ORA_1D

	cmp al,0x19

	je .ORA_19

	cmp al,0x15

	je .ORA_15

	cmp al,0x01

	je .ORA_01

	cmp al,0x11

	je .ORA_11

	cmp al,0x49

	je .EOR_49

	cmp al,0x4D

	je .EOR_4D

	cmp al,0x45

	je .EOR_45

	cmp al,0x5D

	je .EOR_5D

	cmp al,0x59

	je .EOR_59

	cmp al,0x55

	je .EOR_55

	cmp al,0x41

	je .EOR_41

	cmp al,0x51

	je .EOR_51

	cmp al,0x0A

	je .ASL_0A

	cmp al,0x0E

	je .ASL_0E

	cmp al,0x06

	je .ASL_06

	cmp al,0x1E

	je .ASL_1E

	cmp al,0x16

	je .ASL_16

	cmp al,0x4A

	je .LSR_4A

	cmp al,0x4E

	je .LSR_4E

	cmp al,0x46

	je .LSR_46

	cmp al,0x5E

	je .LSR_5E

	cmp al,0x56

	je .LSR_56

	cmp al,0x2A

	je .ROL_2A

	cmp al,0x2E

	je .ROL_2E

	cmp al,0x26

	je .ROL_26

	cmp al,0x3E

	je .ROL_3E

	cmp al,0x36

	je .ROL_36

	cmp al,0x6A

	je .ROR_6A

	cmp al,0x6E

	je .ROR_6E

	cmp al,0x66

	je .ROR_66

	cmp al,0x7E

	je .ROR_7E

	cmp al,0x76

	je .ROR_76

	cmp al,0xA9

	je .LDA_A9

	cmp al,0xAD

	je .LDA_AD

	cmp al,0xA5

	je .LDA_A5

	cmp al,0xBD

	je .LDA_BD

	cmp al,0xB9

	je .LDA_B9

	cmp al,0xB5

	je .LDA_B5

	cmp al,0xA1

	je .LDA_A1

	cmp al,0xB1

	je .LDA_B1

	cmp al,0x8D

	je .STA_8D

	cmp al,0x85

	je .STA_85

	cmp al,0x9D

	je .STA_9D

	cmp al,0x99

	je .STA_99

	cmp al,0x95

	je .STA_95

	cmp al,0x81

	je .STA_81

	cmp al,0x91

	je .STA_91

	cmp al,0xA2

	je .LDX_A2

	cmp al,0xAE

	je .LDX_AE

	cmp al,0xA6

	je .LDX_A6

	cmp al,0xBE

	je .LDX_BE

	cmp al,0xB6

	je .LDX_B6

	cmp al,0xA0

	je .LDY_A0

	cmp al,0xAC

	je .LDY_AC

	cmp al,0xA4

	je .LDY_A4

	cmp al,0xBC

	je .LDY_BC

	cmp al,0xB4

	je .LDY_B4

	cmp al,0x8E

	je .STX_8E

	cmp al,0x86

	je .STX_86

	cmp al,0x96

	je .STX_96

	cmp al,0x8C

	je .STY_8C

	cmp al,0x84

	je .STY_84

	cmp al,0x94

	je .STY_94

	cmp al,0xC9

	je .CMP_C9

	cmp al,0xCD

	je .CMP_CD

	cmp al,0xC5

	je .CMP_C5

	cmp al,0xDD

	je .CMP_DD

	cmp al,0xD9

	je .CMP_D9

	cmp al,0xD5

	je .CMP_D5

	cmp al,0xC1

	je .CMP_C1

	cmp al,0xD1

	je .CMP_D1

	cmp al,0xE0

	je .CPX_E0

	cmp al,0xEC

	je .CPX_EC

	cmp al,0xE4

	je .CPX_E4

	cmp al,0xC0

	je .CPY_C0

	cmp al,0xCC

	je .CPY_CC

	cmp al,0xC4

	je .CPY_C4

	cmp al,0x24

	je .BIT_24

	cmp al,0x2C

	je .BIT_2C

	cmp al,0xEE

	je .INC_EE

	cmp al,0xE6

	je .INC_E6

	cmp al,0xFE

	je .INC_FE

	cmp al,0xF6

	je .INC_F6

	cmp al,0xCE

	je .DEC_CE

	cmp al,0xC6

	je .DEC_C6

	cmp al,0xDE

	je .DEC_DE

	cmp al,0xD6

	je .DEC_D6

	cmp al,0xE8

	je .INX_E8

	cmp al,0xCA

	je .DEX_CA

	cmp al,0xC8

	je .INY_C8

	cmp al,0x88

	je .DEY_88

	cmp al,0x4C

	je .JMP_4C

	cmp al,0x6C

	je .JMP_6C

	cmp al,0x48

	je .PHA_48

	cmp al,0x68

	je .PLA_68

	cmp al,0x08

	je .PHP_08

	cmp al,0x28

	je .PLP_28

	cmp al,0xAA

	je .TAX_AA

	cmp al,0x8A

	je .TXA_8A

	cmp al,0xA8

	je .TAY_A8

	cmp al,0x98

	je .TYA_98

	cmp al,0xBA

	je .TSX_BA

	cmp al,0x9A

	je .TXS_9A

	cmp al,0x18

	je .CLC_18

	cmp al,0x38

	je .SEC_38

	cmp al,0xB8

	je .CLV_B8

	cmp al,0xEA

	je .NOP_EA

	cmp al,0x20

	je .JSR_20

	cmp al,0x60

	je .RTS_60

	cmp al,0x10

	je .BPL_10

	cmp al,0x30

	je .BMI_30

	cmp al,0x50

	je .BVC_50

	cmp al,0x70

	je .BVS_70

	cmp al,0x90

	je .BCC_90

	cmp al,0xB0

	je .BCS_B0

	cmp al,0xD0

	je .BNE_D0

	cmp al,0xF0

	je .BEQ_F0

	jmp .ERROR

  .ADC_69:

	; ADC - immediate mode

	GET_BYTE_IMMED

	xor ah,ah

	mov word [Exe_Info_89],ax

	stdcall ADC_Byte

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x03434441

	jmp .DONE

  .ADC_6D:

	; ADC - absolute mode

	GET_BYTE_ABS

	stdcall ADC_Byte

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x04434441

	jmp .DONE

  .ADC_65:

	; ADC - zero page mode

	GET_BYTE_ZP

	stdcall ADC_Byte

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x05434441

	jmp .DONE

  .ADC_7D:

	; ADC - absolute indexed with X mode

	GET_BYTE_AX

	stdcall ADC_Byte

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x06434441

	jmp .DONE

  .ADC_79:

	; ADC - absolute indexed with Y mode

	GET_BYTE_AY

	stdcall ADC_Byte

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x07434441

	jmp .DONE

  .ADC_75:

	; ADC - zero page indexed with X mode

	GET_BYTE_ZPX

	stdcall ADC_Byte

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x08434441

	jmp .DONE

  .ADC_61:

	; ADC - indexed by X indirect mode

	GET_BYTE_ZPIX

	stdcall ADC_Byte

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0a434441

	jmp .DONE

  .ADC_71:

	; ADC - indirect indexed by Y mode

	GET_BYTE_ZPIY

	stdcall ADC_Byte

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0b434441

	jmp .DONE

  .SBC_E9:

	; SBC - immediate mode

	GET_BYTE_IMMED

	xor ah,ah

	mov word [Exe_Info_89],ax

	stdcall SBC_Byte

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x03434253

	jmp .DONE

  .SBC_ED:

	; SBC - absolute mode

	GET_BYTE_ABS

	stdcall SBC_Byte

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x04434253

	jmp .DONE

  .SBC_E5:

	; SBC - zero page mode

	GET_BYTE_ZP

	stdcall SBC_Byte

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x05434253

	jmp .DONE

  .SBC_FD:

	; SBC - absolute indexed with X mode

	GET_BYTE_AX

	stdcall SBC_Byte

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x06434253

	jmp .DONE

  .SBC_F9:

	; SBC - absolute indexed with Y mode

	GET_BYTE_AY

	stdcall SBC_Byte

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x07434253

	jmp .DONE

  .SBC_F5:

	; SBC - zero page indexed with X mode

	GET_BYTE_ZPX

	stdcall SBC_Byte

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x08434253

	jmp .DONE

  .SBC_E1:

	; SBC - indexed by X indirect mode

	GET_BYTE_ZPIX

	stdcall SBC_Byte

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0a434253

	jmp .DONE

  .SBC_F1:

	; SBC - indirect indexed by Y mode

	GET_BYTE_ZPIY

	stdcall SBC_Byte

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0b434253

	jmp .DONE

  .AND_29:

	; AND - immediate mode

	GET_BYTE_IMMED

	xor ah,ah

	mov word [Exe_Info_89],ax

	and al,[Accumulator]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x03444e41

	jmp .DONE

  .AND_2D:

	; AND - absolute mode

	GET_BYTE_ABS

	and al,[Accumulator]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x04444e41

	jmp .DONE

  .AND_25:

	; AND - zero page mode

	GET_BYTE_ZP

	and al,[Accumulator]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x05444e41

	jmp .DONE

  .AND_3D:

	; AND - absolute indexed with X mode

	GET_BYTE_AX

	and al,[Accumulator]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x06444e41

	jmp .DONE

  .AND_39:

	; AND - absolute indexed with Y mode

	GET_BYTE_AY

	and al,[Accumulator]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x07444e41

	jmp .DONE

  .AND_35:

	; AND - zero page indexed with X mode

	GET_BYTE_ZPX

	and al,[Accumulator]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x08444e41

	jmp .DONE

  .AND_21:

	; AND - indexed by X indirect mode

	GET_BYTE_ZPIX

	and al,[Accumulator]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0a444e41

	jmp .DONE

  .AND_31:

	; AND - indirect indexed by Y mode

	GET_BYTE_ZPIY

	and al,[Accumulator]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0b444e41

	jmp .DONE

  .ORA_09:

	; ORA - immediate mode

	GET_BYTE_IMMED

	xor ah,ah

	mov word [Exe_Info_89],ax

	or al,[Accumulator]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0341524f

	jmp .DONE

  .ORA_0D:

	; ORA - absolute mode

	GET_BYTE_ABS

	or al,[Accumulator]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0441524f

	jmp .DONE

  .ORA_05:

	; ORA - zero page mode

	GET_BYTE_ZP

	or al,[Accumulator]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0541524f

	jmp .DONE

  .ORA_1D:

	; ORA - absolute indexed with X mode

	GET_BYTE_AX

	or al,[Accumulator]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0641524f

	jmp .DONE

  .ORA_19:

	; ORA - absolute indexed with Y mode

	GET_BYTE_AY

	or al,[Accumulator]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0741524f

	jmp .DONE

  .ORA_15:

	; ORA - zero page indexed with X mode

	GET_BYTE_ZPX

	or al,[Accumulator]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0841524f

	jmp .DONE

  .ORA_01:

	; ORA - indexed by X indirect mode

	GET_BYTE_ZPIX

	or al,[Accumulator]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0a41524f

	jmp .DONE

  .ORA_11:

	; ORA - indirect indexed by Y mode

	GET_BYTE_ZPIY

	or al,[Accumulator]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0b41524f

	jmp .DONE

  .EOR_49:

	; EOR - immediate mode

	GET_BYTE_IMMED

	xor ah,ah

	mov word [Exe_Info_89],ax

	xor al,[Accumulator]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x03524f45

	jmp .DONE

  .EOR_4D:

	; EOR - absolute mode

	GET_BYTE_ABS

	xor al,[Accumulator]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x04524f45

	jmp .DONE

  .EOR_45:

	; EOR - zero page mode

	GET_BYTE_ZP

	xor al,[Accumulator]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x05524f45

	jmp .DONE

  .EOR_5D:

	; EOR - absolute indexed with X mode

	GET_BYTE_AX

	xor al,[Accumulator]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x06524f45

	jmp .DONE

  .EOR_59:

	; EOR - absolute indexed with Y mode

	GET_BYTE_AY

	xor al,[Accumulator]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x07524f45

	jmp .DONE

  .EOR_55:

	; EOR - zero page indexed with X mode

	GET_BYTE_ZPX

	xor al,[Accumulator]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x08524f45

	jmp .DONE

  .EOR_41:

	; EOR - indexed by X indirect mode

	GET_BYTE_ZPIX

	xor al,[Accumulator]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0a524f45

	jmp .DONE

  .EOR_51:

	; EOR - indirect indexed by Y mode

	GET_BYTE_ZPIY

	xor al,[Accumulator]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0b524f45

	jmp .DONE

  .ASL_0A:

	; ASL - accumulator mode

	inc cx

	mov al,[Accumulator]

	stdcall ASL_Byte

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x004c5341

	jmp .DONE

  .ASL_0E:

	; ASL - absolute mode

	GET_BYTE_ABS

	stdcall ASL_Byte

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x044c5341

	jmp .DONE

  .ASL_06:

	; ASL - zero page mode

	GET_BYTE_ZP

	stdcall ASL_Byte

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x054c5341

	jmp .DONE

  .ASL_1E:

	; ASL - absolute indexed with X mode

	GET_BYTE_AX

	stdcall ASL_Byte

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x064c5341

	jmp .DONE

  .ASL_16:

	; ASL - zero page indexed with X mode

	GET_BYTE_ZPX

	stdcall ASL_Byte

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x084c5341

	jmp .DONE

  .LSR_4A:

	; LSR - accumulator mode

	inc cx

	mov al,[Accumulator]

	stdcall LSR_Byte

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0052534c

	jmp .DONE

  .LSR_4E:

	; LSR - absolute mode

	GET_BYTE_ABS

	stdcall LSR_Byte

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x0452534c

	jmp .DONE

  .LSR_46:

	; LSR - zero page mode

	GET_BYTE_ZP

	stdcall LSR_Byte

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x0552534c

	jmp .DONE

  .LSR_5E:

	; LSR - absolute indexed with X mode

	GET_BYTE_AX

	stdcall LSR_Byte

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x0652534c

	jmp .DONE

  .LSR_56:

	; LSR - zero page indexed with X mode

	GET_BYTE_ZPX

	stdcall LSR_Byte

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x0852534c

	jmp .DONE

  .ROL_2A:

	; ROL - accumulator mode

	inc cx

	mov al,[Accumulator]

	stdcall ROL_Byte

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x004c4f52

	jmp .DONE

  .ROL_2E:

	; ROL - absolute mode

	GET_BYTE_ABS

	stdcall ROL_Byte

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x044c4f52

	jmp .DONE

  .ROL_26:

	; ROL - zero page mode

	GET_BYTE_ZP

	stdcall ROL_Byte

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x054c4f52

	jmp .DONE

  .ROL_3E:

	; ROL - absolute indexed with X mode

	GET_BYTE_AX

	stdcall ROL_Byte

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x064c4f52

	jmp .DONE

  .ROL_36:

	; ROL - zero page indexed with X mode

	GET_BYTE_ZPX

	stdcall ROL_Byte

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x084c4f52

	jmp .DONE

  .ROR_6A:

	; ROR - accumulator mode

	inc cx

	mov al,[Accumulator]

	stdcall ROR_Byte

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x00524f52

	jmp .DONE

  .ROR_6E:

	; ROR - absolute mode

	GET_BYTE_ABS

	stdcall ROR_Byte

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x04524f52

	jmp .DONE

  .ROR_66:

	; ROR - zero page mode

	GET_BYTE_ZP

	stdcall ROR_Byte

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x05524f52

	jmp .DONE

  .ROR_7E:

	; ROR - absolute indexed with X mode

	GET_BYTE_AX

	stdcall ROR_Byte

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x06524f52

	jmp .DONE

  .ROR_76:

	; ROR - zero page indexed with X mode

	GET_BYTE_ZPX

	stdcall ROR_Byte

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x08524f52

	jmp .DONE

  .LDA_A9:

	; LDA - immediate mode

	GET_BYTE_IMMED

	stdcall Set_ZN

	xor ah,ah

	mov word [Exe_Info_89],ax

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0341444c

	jmp .DONE

  .LDA_AD:

	; LDA - absolute mode

	GET_BYTE_ABS

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0441444c

	jmp .DONE

  .LDA_A5:

	; LDA - zero page mode

	GET_BYTE_ZP

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0541444c

	jmp .DONE

  .LDA_BD:

	; LDA - absolute indexed with X mode

	GET_BYTE_AX

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0641444c

	jmp .DONE

  .LDA_B9:

	; LDA - absolute indexed with Y mode

	GET_BYTE_AY

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0741444c

	jmp .DONE

  .LDA_B5:

	; LDA - zero page indexed with X mode

	GET_BYTE_ZPX

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0841444c

	jmp .DONE

  .LDA_A1:

	; LDA - indexed by X indirect mode

	GET_BYTE_ZPIX

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0a41444c

	jmp .DONE

  .LDA_B1:

	; LDA - indirect indexed by Y mode

	GET_BYTE_ZPIY

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x0b41444c

	jmp .DONE

  .STA_8D:

	; STA - absolute mode

	inc cx

	xor edx,edx

	mov dx,[esi+ecx]

	mov word [Exe_Info_67],dx

	add cx,2

	mov al,[Accumulator]

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x04415453

	jmp .DONE

  .STA_85:

	; STA - zero page mode

	inc cx

	xor edx,edx

	mov dl,[esi+ecx]

	mov word [Exe_Info_67],dx

	inc cx

	mov al,[Accumulator]

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x05415453

	jmp .DONE

  .STA_9D:

	; STA - absolute indexed with X mode

	inc cx

	xor edx,edx

	mov dx,[esi+ecx]

	add cx,2

	add dl,[Index_Reg_X]

	adc dh,0

	mov word [Exe_Info_67],dx

	mov al,[Accumulator]

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x06415453

	jmp .DONE

  .STA_99:

	; STA - absolute indexed with Y mode

	inc cx

	xor edx,edx

	mov dx,[esi+ecx]

	add cx,2

	add dl,[Index_Reg_Y]

	adc dh,0

	mov al,[Accumulator]

	mov word [Exe_Info_67],dx

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x07415453

	jmp .DONE

  .STA_95:

	; STA - zero page indexed with X mode

	inc cx

	xor edx,edx

	mov dl,[esi+ecx]

	add dl,[Index_Reg_X]

	mov word [Exe_Info_67],dx

	inc cx

	mov al,[Accumulator]

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x08415453

	jmp .DONE

  .STA_81:

	; STA - indexed by X indirect mode

	inc cx

	xor edx,edx

	; get the byte that stores the zero page address

	mov dl,[esi+ecx]

	inc cx

	; add X to the zero page address (result wraps to a zero page address)

	add dl,[Index_Reg_X]

	; read the 2 byte target address stored at the zero page address

	mov dx,[esi+edx]

	mov word [Exe_Info_67],dx

	; do the STA operation

	mov al,[Accumulator]

	; set the byte at the target address

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x0a415453

	jmp .DONE

  .STA_91:

	; STA - indirect indexed by Y mode

	inc cx

	xor edx,edx

	; get the byte that stores the zero page address of the target address

	mov dl,[esi+ecx]

	inc cx

	; read the 2 byte target address stored at the zero page address

	mov dx,[esi+edx]

	; add Y to the target address

	add dl,[Index_Reg_Y]

	adc dh,0

	mov word [Exe_Info_67],dx

	; do the STA operation

	mov al,[Accumulator]

	; set the byte at the target address

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x0b415453

	jmp .DONE

  .LDX_A2:

	; LDX - immediate mode

	GET_BYTE_IMMED

	stdcall Set_ZN

	xor ah,ah

	mov word [Exe_Info_89],ax

	mov [Index_Reg_X],al

	mov dword [Exe_Info_2345],0x0358444c

	jmp .DONE

  .LDX_AE:

	; LDX - absolute mode

	GET_BYTE_ABS

	stdcall Set_ZN

	mov [Index_Reg_X],al

	mov dword [Exe_Info_2345],0x0458444c

	jmp .DONE

  .LDX_A6:

	; LDX - zero page mode

	GET_BYTE_ZP

	stdcall Set_ZN

	mov [Index_Reg_X],al

	mov dword [Exe_Info_2345],0x0558444c

	jmp .DONE

  .LDX_BE:

	; LDX - absolute indexed with Y mode

	GET_BYTE_AY

	stdcall Set_ZN

	mov [Index_Reg_X],al

	mov dword [Exe_Info_2345],0x0758444c

	jmp .DONE

  .LDX_B6:

	; LDX - zero page indexed with Y mode

	GET_BYTE_ZPY

	stdcall Set_ZN

	mov [Index_Reg_X],al

	mov dword [Exe_Info_2345],0x0958444c

	jmp .DONE

  .LDY_A0:

	; LDY - immediate mode

	GET_BYTE_IMMED

	stdcall Set_ZN

	xor ah,ah

	mov word [Exe_Info_89],ax

	mov [Index_Reg_Y],al

	mov dword [Exe_Info_2345],0x0359444c

	jmp .DONE

  .LDY_AC:

	; LDY - absolute mode

	GET_BYTE_ABS

	stdcall Set_ZN

	mov [Index_Reg_Y],al

	mov dword [Exe_Info_2345],0x0459444c

	jmp .DONE

  .LDY_A4:

	; LDY - zero page mode

	GET_BYTE_ZP

	stdcall Set_ZN

	mov [Index_Reg_Y],al

	mov dword [Exe_Info_2345],0x0559444c

	jmp .DONE

  .LDY_BC:

	; LDY - absolute indexed with X mode

	GET_BYTE_AX

	stdcall Set_ZN

	mov [Index_Reg_Y],al

	mov dword [Exe_Info_2345],0x0659444c

	jmp .DONE

  .LDY_B4:

	; LDY - zero page indexed with X mode

	GET_BYTE_ZPX

	stdcall Set_ZN

	mov [Index_Reg_Y],al

	mov dword [Exe_Info_2345],0x0859444c

	jmp .DONE

  .STX_8E:

	; STX - absolute mode

	inc cx

	xor edx,edx

	mov dx,[esi+ecx]

	mov word [Exe_Info_67],dx

	add cx,2

	mov al,[Index_Reg_X]

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x04585453

	jmp .DONE

  .STX_86:

	; STX - zero page mode

	inc cx

	xor edx,edx

	mov dl,[esi+ecx]

	mov word [Exe_Info_67],dx

	inc cx

	mov al,[Index_Reg_X]

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x05585453

	jmp .DONE

  .STX_96:

	; STX - zero page indexed with Y mode

	inc cx

	xor edx,edx

	mov dl,[esi+ecx]

	add dl,[Index_Reg_Y]

	mov word [Exe_Info_67],dx

	inc cx

	mov al,[Index_Reg_X]

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x09585453

	jmp .DONE

  .STY_8C:

	; STY - absolute mode

	inc cx

	xor edx,edx

	mov dx,[esi+ecx]

	mov word [Exe_Info_67],dx

	add cx,2

	mov al,[Index_Reg_Y]

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x04595453

	jmp .DONE

  .STY_84:

	; STY - zero page mode

	inc cx

	xor edx,edx

	mov dl,[esi+ecx]

	mov word [Exe_Info_67],dx

	inc cx

	mov al,[Index_Reg_Y]

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x05595453

	jmp .DONE

  .STY_94:

	; STY - zero page indexed with X mode

	inc cx

	xor edx,edx

	mov dl,[esi+ecx]

	add dl,[Index_Reg_X]

	mov word [Exe_Info_67],dx

	inc cx

	mov al,[Index_Reg_Y]

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x08595453

	jmp .DONE

  .CMP_C9:

	; CMP - immediate mode

	GET_BYTE_IMMED

	xor ah,ah

	mov word [Exe_Info_89],ax

	stdcall CMP_Byte

	mov dword [Exe_Info_2345],0x03504d43

	jmp .DONE

  .CMP_CD:

	; CMP - absolute mode

	GET_BYTE_ABS

	stdcall CMP_Byte

	mov dword [Exe_Info_2345],0x04504d43

	jmp .DONE

  .CMP_C5:

	; CMP - zero page mode

	GET_BYTE_ZP

	stdcall CMP_Byte

	mov dword [Exe_Info_2345],0x05504d43

	jmp .DONE

  .CMP_DD:

	; CMP - absolute indexed with X mode

	GET_BYTE_AX

	stdcall CMP_Byte

	mov dword [Exe_Info_2345],0x06504d43

	jmp .DONE

  .CMP_D9:

	; CMP - absolute indexed with Y mode

	GET_BYTE_AY

	stdcall CMP_Byte

	mov dword [Exe_Info_2345],0x07504d43

	jmp .DONE

  .CMP_D5:

	; CMP - zero page indexed with X mode

	GET_BYTE_ZPX

	stdcall CMP_Byte

	mov dword [Exe_Info_2345],0x08504d43

	jmp .DONE

  .CMP_C1:

	; CMP - indexed by X indirect mode

	GET_BYTE_ZPIX

	; do the CMP operation

	stdcall CMP_Byte

	mov dword [Exe_Info_2345],0x0a504d43

	jmp .DONE

  .CMP_D1:

	; CMP - indirect indexed by Y mode

	GET_BYTE_ZPIY

	; do the CMP operation

	stdcall CMP_Byte

	mov dword [Exe_Info_2345],0x0b504d43

	jmp .DONE

  .CPX_E0:

	; CPX - immediate mode

	GET_BYTE_IMMED

	xor ah,ah

	mov word [Exe_Info_89],ax

	stdcall CPX_Byte

	mov dword [Exe_Info_2345],0x03585043

	jmp .DONE

  .CPX_EC:

	; CPX - absolute mode

	GET_BYTE_ABS

	stdcall CPX_Byte

	mov dword [Exe_Info_2345],0x04585043

	jmp .DONE

  .CPX_E4:

	; CPX - zero page mode

	GET_BYTE_ZP

	stdcall CPX_Byte

	mov dword [Exe_Info_2345],0x05585043

	jmp .DONE

  .CPY_C0:

	; CPY - immediate mode

	GET_BYTE_IMMED

	xor ah,ah

	mov word [Exe_Info_89],ax

	stdcall CPY_Byte

	mov dword [Exe_Info_2345],0x03595043

	jmp .DONE

  .CPY_CC:

	; CPY - absolute mode

	GET_BYTE_ABS

	stdcall CPY_Byte

	mov dword [Exe_Info_2345],0x04595043

	jmp .DONE

  .CPY_C4:

	; CPY - zero page mode

	GET_BYTE_ZP

	stdcall CPY_Byte

	mov dword [Exe_Info_2345],0x05595043

	jmp .DONE

  .BIT_24:

	; BIT - zero page mode

	GET_BYTE_ZP

	stdcall Test_BIT

	mov dword [Exe_Info_2345],0x05544942

	jmp .DONE

  .BIT_2C:

	; BIT - absolute mode

	GET_BYTE_ABS

	stdcall Test_BIT

	mov dword [Exe_Info_2345],0x04544942

	jmp .DONE

  .INC_EE:

	; INC - absolute mode

	GET_BYTE_ABS

	inc al

	stdcall Set_ZN

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x04434e49

	jmp .DONE

  .INC_E6:

	; INC - zero page mode

	GET_BYTE_ZP

	inc al

	stdcall Set_ZN

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x05434e49

	jmp .DONE

  .INC_FE:

	; INC - absolute indexed with X mode

	GET_BYTE_AX

	inc al

	stdcall Set_ZN

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x06434e49

	jmp .DONE

  .INC_F6:

	; INC - zero page indexed with X mode

	GET_BYTE_ZPX

	inc al

	stdcall Set_ZN

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x08434e49

	jmp .DONE

  .DEC_CE:

	; DEC - absolute mode

	GET_BYTE_ABS

	dec al

	stdcall Set_ZN

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x04434544

	jmp .DONE

  .DEC_C6:

	; DEC - zero page mode

	GET_BYTE_ZP

	dec al

	stdcall Set_ZN

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x05434544

	jmp .DONE

  .DEC_DE:

	; DEC - absolute indexed with X mode

	GET_BYTE_AX

	dec al

	stdcall Set_ZN

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x06434544

	jmp .DONE

  .DEC_D6:

	; DEC - zero page indexed with X mode

	GET_BYTE_ZPX

	dec al

	stdcall Set_ZN

	mov [esi+edx],al

	mov dword [Exe_Info_2345],0x08434544

	jmp .DONE

  .INX_E8:

	; INX - implied mode

	inc cx

	mov al,[Index_Reg_X]

	inc al

	stdcall Set_ZN

	mov [Index_Reg_X],al

	mov dword [Exe_Info_2345],0x01584e49

	jmp .DONE

  .DEX_CA:

	; DEX - implied mode

	inc cx

	mov al,[Index_Reg_X]

	dec al

	stdcall Set_ZN

	mov [Index_Reg_X],al

	mov dword [Exe_Info_2345],0x01584544

	jmp .DONE

  .INY_C8:

	; INY - implied mode

	inc cx

	mov al,[Index_Reg_Y]

	inc al

	stdcall Set_ZN

	mov [Index_Reg_Y],al

	mov dword [Exe_Info_2345],0x01594e49

	jmp .DONE

  .DEY_88:

	; DEY - implied mode

	inc cx

	mov al,[Index_Reg_Y]

	dec al

	stdcall Set_ZN

	mov [Index_Reg_Y],al

	mov dword [Exe_Info_2345],0x01594544

	jmp .DONE

  .JMP_4C:

	; JMP - absolute mode

	inc cx

	xor edx,edx

	; get the target address

	mov dx,[esi+ecx]

	mov word [Exe_Info_67],dx

	add cx,2

	; load the target address into the program counter (CX)

	mov cx,dx

	mov dword [Exe_Info_2345],0x04504d4a

	jmp .DONE

  .JMP_6C:

	; JMP - indirect mode

	inc cx

	xor edx,edx

	; get the address of the target address

	mov dx,[esi+ecx]

	add cx,2

	; get the target address

	mov dx,[esi+edx]

	mov word [Exe_Info_67],dx

	; load the target address into the program counter (CX)

	mov cx,dx

	mov dword [Exe_Info_2345],0x0c504d4a

	jmp .DONE

  .PHA_48:

	; PHA - implied mode

	; push Acc to the stack

	inc cx

	mov al,[Accumulator]

	stdcall Push_Byte

	mov dword [Exe_Info_2345],0x01414850

	jmp .DONE

  .PLA_68:

	; PLA - implied mode

	; pull Acc from the stack

	inc cx

	stdcall Pull_Byte

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x01414c50

	jmp .DONE

  .PHP_08:

	; PHP - implied mode

	; push NV_ZC (the processor status) to the stack

	inc cx

	mov al,[NV_ZC]

	stdcall Push_Byte

	mov dword [Exe_Info_2345],0x01504850

	jmp .DONE

  .PLP_28:

	; PLP - implied mode

	; pull NV_ZC (the processor status) from the stack

	inc cx

	stdcall Pull_Byte

	mov [NV_ZC],al

	mov dword [Exe_Info_2345],0x01504c50

	jmp .DONE

  .TAX_AA:

	; TAX - implied mode

	; set X = ACC

	inc cx

	mov al,[Accumulator]

	stdcall Set_ZN

	mov [Index_Reg_X],al

	mov dword [Exe_Info_2345],0x01584154

	jmp .DONE

  .TXA_8A:

	; TXA - implied mode

	; set ACC = X

	inc cx

	mov al,[Index_Reg_X]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x01415854

	jmp .DONE

  .TAY_A8:

	; TAY - implied mode

	; set Y = ACC

	inc cx

	mov al,[Accumulator]

	stdcall Set_ZN

	mov [Index_Reg_Y],al

	mov dword [Exe_Info_2345],0x01594154

	jmp .DONE

  .TYA_98:

	; TYA - implied mode

	; set ACC = Y

	inc cx

	mov al,[Index_Reg_Y]

	stdcall Set_ZN

	mov [Accumulator],al

	mov dword [Exe_Info_2345],0x01415954

	jmp .DONE

  .TSX_BA:

	; TSX - implied mode

	; set X = Stack_Pointer

	inc cx

	mov al,[Stack_Pointer]

	stdcall Set_ZN

	mov [Index_Reg_X],al

	mov dword [Exe_Info_2345],0x01585354

	jmp .DONE

  .TXS_9A:

	; TXS - implied mode

	; set Stack_Pointer = X

	inc cx

	mov al,[Index_Reg_X]

	mov [Stack_Pointer],al

	mov dword [Exe_Info_2345],0x01535854

	jmp .DONE

  .CLC_18:

	; CLC - clear the carry flag

	inc cx

	and [NV_ZC],byte 0xfe

	mov dword [Exe_Info_2345],0x01434c43

	jmp .DONE

  .SEC_38:

	; SEC - set the carry flag

	inc cx

	or [NV_ZC],byte 1

	mov dword [Exe_Info_2345],0x01434553

	jmp .DONE

  .CLV_B8:

	; CLV - clear the overflow flag

	inc cx

	and [NV_ZC],byte 0x8f

	mov dword [Exe_Info_2345],0x01564c43

	jmp .DONE

  .NOP_EA:

	; NOP - do nothing - just increment CX

	inc cx

	mov dword [Exe_Info_2345],0x01504f4e

	jmp .DONE

  .JSR_20:

	; JSR - absolute mode

	inc cx

	xor edx,edx

	; get the address to jump to

	mov dx,[esi+ecx]

	mov word [Exe_Info_67],dx

	inc cx

	; get the return address minus 1

	mov ax,cx

	; push the return address minus 1 to the stack

	; high byte

	mov al,ah

	stdcall Push_Byte

	; low byte

	mov ax,cx

	stdcall Push_Byte

	; set the program counter to the target address (DX)

	mov cx,dx

	mov dword [Exe_Info_2345],0x0452534a

	jmp .DONE

  .RTS_60:

	; pull the return address minus 1 from the stack

	; low byte

	stdcall Pull_Byte

	mov cl,al

	; high byte

	stdcall Pull_Byte

	mov ch,al

	; increment the program counter

	inc cx

	mov dword [Exe_Info_2345],0x01535452

	jmp .DONE

  .BPL_10:

	; BPL - relative mode

	; branch if N = 0

	mov dword [Exe_Info_2345],0x024c5042

	; put the relative offset into AL

	GET_BYTE_IMMED

	; test N

	mov dl,[NV_ZC]

	and dl,0x80

	jnz .DONE

	stdcall Add_Relative

	jmp .DONE

  .BMI_30:

	; BMI - relative mode

	; branch if N = 1

	mov dword [Exe_Info_2345],0x02494d42

	; put the relative offset into AL

	GET_BYTE_IMMED

	; test N

	mov dl,[NV_ZC]

	and dl,0x80

	jz .DONE

	stdcall Add_Relative

	jmp .DONE

  .BVC_50:

	; BVC - relative mode

	; branch if V = 0

	mov dword [Exe_Info_2345],0x02435642

	; put the relative offset into AL

	GET_BYTE_IMMED

	; test V

	mov dl,[NV_ZC]

	and dl,0x40

	jnz .DONE

	stdcall Add_Relative

	jmp .DONE

  .BVS_70:

	; BVS - relative mode

	; branch if V = 1

	mov dword [Exe_Info_2345],0x02535642

	; put the relative offset into AL

	GET_BYTE_IMMED

	; test V

	mov dl,[NV_ZC]

	and dl,0x40

	jz .DONE

	stdcall Add_Relative

	jmp .DONE

  .BCC_90:

	; BCC - relative mode

	; branch if C = 0

	mov dword [Exe_Info_2345],0x02434342

	; put the relative offset into AL

	GET_BYTE_IMMED

	; test C

	mov dl,[NV_ZC]

	and dl,1

	jnz .DONE

	stdcall Add_Relative

	jmp .DONE

  .BCS_B0:

	; BCS - relative mode

	; branch if C = 1

	mov dword [Exe_Info_2345],0x02534342

	; put the relative offset into AL

	GET_BYTE_IMMED

	; test C

	mov dl,[NV_ZC]

	and dl,1

	jz .DONE

	stdcall Add_Relative

	jmp .DONE

  .BNE_D0:

	; BNE - relative mode

	; branch if Z = 0

	mov dword [Exe_Info_2345],0x02454e42

	; put the relative offset into AL

	GET_BYTE_IMMED

	; test Z

	mov dl,[NV_ZC]

	and dl,2

	jnz .DONE

	stdcall Add_Relative

	jmp .DONE

  .BEQ_F0:

	; BEQ - relative mode

	; branch if Z = 1

	mov dword [Exe_Info_2345],0x02514542

	; put the relative offset into AL

	GET_BYTE_IMMED

	; test Z

	mov dl,[NV_ZC]

	and dl,2

	jz .DONE

	stdcall Add_Relative

	jmp .DONE

  .ERROR:

	; unknown instruction

	mov byte [Debug_Code],al

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc ASL_Byte

  ; shift left AL by 1 bit and set the CZN flags

	; clear the C flag

	and [NV_ZC],byte 0xfe

	shl al,1

	jnc .ZN

	; set the C flag

	or [NV_ZC],byte 1

  .ZN:

	stdcall Set_ZN

	ret

endp

; -------------------------------------------------------------------------------------

proc LSR_Byte

  ; shift right AL by 1 bit and set the CZN flags

	; clear the C flag

	and [NV_ZC],byte 0xfe

	shr al,1

	jnc .ZN

	; set the C flag

	or [NV_ZC],byte 1

  .ZN:

	stdcall Set_ZN

	ret

endp

; -------------------------------------------------------------------------------------

proc ROL_Byte

  ; rotate left AL by 1 bit (through the C bit) and set the CZN flags

	; store the C flag in AH

	mov ah,byte [NV_ZC]

	and ah,1

	; clear the C flag

	and [NV_ZC],byte 0xfe

	; shift left

	shl al,1

	jnc .NC

	; set the C flag

	or [NV_ZC],byte 1

  .NC:

	; complete the ROL by adding the bit that was stored in the C flag

	or al,ah

  .ZN:

	stdcall Set_ZN

	ret

endp

; -------------------------------------------------------------------------------------

proc ROR_Byte

  ; rotate right AL by 1 bit (through the C bit) and set the CZN flags

	; store the C flag in AH

	mov ah,byte [NV_ZC]

	and ah,1

	; clear the C flag

	and [NV_ZC],byte 0xfe

	; shift right

	shr al,1

	jnc .NC

	; set the C flag

	or [NV_ZC],byte 1

  .NC:

	; complete the ROL by adding the bit that was stored in the C flag

	ror ah,1

	or al,ah

  .ZN:

	stdcall Set_ZN

	ret

endp

; -------------------------------------------------------------------------------------

proc CMP_Byte uses ebx

  ; compare the byte passed in AL to the accumulator

	mov bl,byte [Accumulator]

	; clear the C flag

	and [NV_ZC],byte 0xfe

	; CMP = BL - AL

	cmp bl,al

	jl .ZN

	; set the C flag

	or byte [NV_ZC],1

  .ZN:

	; set the Z and N flags

	sub bl,al

	; put the result back into AL

	mov al,bl

	stdcall Set_ZN

	ret

endp

; -------------------------------------------------------------------------------------

proc CPX_Byte uses ebx

  ; compare the byte passed in AL to the X register

	mov bl,byte [Index_Reg_X]

	; clear the C flag

	and [NV_ZC],byte 0xfe

	; CPX = BL - AL

	cmp bl,al

	jl .ZN

	; set the C flag

	or byte [NV_ZC],1

  .ZN:

	; set the Z and N flags

	sub bl,al

	; put the result back into AL

	mov al,bl

	stdcall Set_ZN

	ret

endp

; -------------------------------------------------------------------------------------

proc CPY_Byte uses ebx

  ; compare the byte passed in AL to the Y register

	mov bl,byte [Index_Reg_Y]

	; clear the C flag

	and [NV_ZC],byte 0xfe

	; CPY = BL - AL

	cmp bl,al

	jl .ZN

	; set the C flag

	or byte [NV_ZC],1

  .ZN:

	; set the Z and N flags

	sub bl,al

	; put the result back into AL

	mov al,bl

	stdcall Set_ZN

	ret

endp

; -------------------------------------------------------------------------------------

proc ADC_Byte uses ebx

  ; to the accumulator: add the byte in AL and the C bit

  ; the result is returned in AL

	; save the C bit to BL

	mov bl,byte [NV_ZC]

	; clear the V and C bits

	and [NV_ZC],byte 0x82

	; use the value of BL to set the x86 carry bit

	clc

	and bl,1

	jz .ADD

	stc

  .ADD:

	; copy the accumulator to BL

	mov bl,byte [Accumulator]

	; ADC to AL

	adc al,bl

	; set the V and C bits

	pushfw

	pop bx

	and bl,1

	or [NV_ZC],bl

	mov bl,bh

	and bl,8

	shl bl,3

	or [NV_ZC],bl

  .ZN:

	; set the Z and N flags (based on the value of AL)

	stdcall Set_ZN

	ret

endp

; -------------------------------------------------------------------------------------

proc SBC_Byte

  ; subtract the byte in AL from the accumulator

  ; calculate as: ACC + not(AL) + C

  ; the result is returned in AL

	; put the value of the accumulator into AH

	mov ah,byte [Accumulator]

	; invert AL

	xor al,0xFF

	; save the C bit to BL

	mov bl,byte [NV_ZC]

	; clear the V and C bits

	and [NV_ZC],byte 0x82

	; use the value of BL to set the x86 carry bit

	clc

	and bl,1

	jz .SUB

	stc

  .SUB:

	; ADC the bytes AL and AH

	adc al,ah

	; set the V and C bits

	pushfw

	pop bx

	and bl,1

	or [NV_ZC],bl

	mov bl,bh

	and bl,8

	shl bl,3

	or [NV_ZC],bl

  .ZN:

	; set the Z and N flags (based on the value of AL)

	stdcall Set_ZN

	ret

endp

; -------------------------------------------------------------------------------------

proc Add_Relative

  ; add or subtract the offset in AL to the program counter (CX)

	mov ah,0

	mov dl,al

	and dl,0x80

	jnz .SUB

  .ADD:

	add cx,ax

	jmp .DONE

  .SUB:

	mov ah,0xff

	add cx,ax

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Test_BIT

  ; test the value in AL against the Accumulator

  ; for the 6502 BIT operation

	; set the flags

	mov dl,[NV_ZC]

	; C is unaffected

	and dl,1

	; set N to bit 7 of AL

	; set V to bit 6 of AL

	mov ah,al

	and ah,0xc0

	or dl,ah

	; AND to set the Z flag

	mov ah,[Accumulator]

	and al,ah

	cmp al,0

	je .DONE

	or dl,2

  .DONE:

	mov [NV_ZC],dl

	ret

endp

; -------------------------------------------------------------------------------------

proc Push_Byte uses edi edx

  ; push a byte to the stack

  ; the byte is passed in AL

	lea edi,[Main_Memory]

	xor edx,edx

	mov dl,[Stack_Pointer]

	add edx,0x100

	; push the byte to the stack

	mov [edi+edx],al

	; decrement the stack pointer

	dec dl

	; update the stack pointer

	mov [Stack_Pointer],dl

	ret

endp

; -------------------------------------------------------------------------------------

proc Pull_Byte uses edi edx

  ; pull a byte from the stack

  ; the byte is returned in AL

	lea edi,[Main_Memory]

	xor edx,edx

	mov dl,[Stack_Pointer]

	; increment the stack pointer

	inc dl

	; update the stack pointer

	mov [Stack_Pointer],dl

	; pull the byte from the stack

	add edx,0x100

	mov al,[edi+edx]

	ret

endp

; -------------------------------------------------------------------------------------

proc Set_ZN

  ; set the flags Z and N based on the value of AL

	; clear Z and N

	and [NV_ZC],byte 0x41

  .Z:

	cmp al,0

	jne .N

	or [NV_ZC],byte 2

  .N:

	mov ah,al

	and ah,0x80

	cmp ah,0

	je .DONE

	or [NV_ZC],byte 0x80

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Reset_Machine

  ; reset all memory and registers to zero

	lea edi,[Main_Memory]

	xor ecx,ecx

  .CLEAR:

	mov [edi],dword 0

	add edi,4

	inc cx

	cmp cx,16384

	jl .CLEAR

	; clear the registers

	mov [Accumulator],byte 0

	mov [Index_Reg_X],byte 0

	mov [Index_Reg_Y],byte 0

	mov [Stack_Pointer],byte 0xff

	mov [NV_ZC],byte 0

	mov [Program_Counter],word 0x200

	mov [Location_Counter],word 0x200

	stdcall Reset_Symbol_Pointer

	ret

endp

; -------------------------------------------------------------------------------------

proc Reset_Edit_Buffers

  ; reset the edit buffers

	lea esi,[szInputText]

	lea edi,[bfAsmCode]

  .COPY:

	mov al,[esi]

	cmp al,0

	je .DONE

	mov [edi],al

	inc esi

	inc edi

	jmp .COPY

  .DONE:

	mov [edi],byte 0

	mov [bfOutput],byte 0

	ret

endp

; -------------------------------------------------------------------------------------

proc Print_Page uses ebx

  ; print the 512 bytes of the two currently selected pages of memory

	lea edi,[bfDisplay]

	lea esi,[Main_Memory]

	; offset from start of memory in bytes passed in EDX

	add esi,edx

	xor ecx,ecx

	; print the address of the row (in DX)

	mov al,dh

	stdcall Byte_To_Hex

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

	mov al,dl

	stdcall Byte_To_Hex

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

	mov [edi],dword 0x20203A20

	add edi,4

  .PRINT:

	stdcall Byte_To_Ascii

	mov [edi],byte 32

	inc edi

	inc cx

	cmp cx,256

	jne .CRLF

	; print an extra CRLF after the first 256 bytes

	PRINT_CRLF

  .CRLF:

	; print a CRLF after every 16 bytes

	mov bx,cx

	and bx,15

	cmp bx,0

	jg .NEXT

	PRINT_CRLF

	; print the address of the row (in DX)

	cmp cx,512

	je .NULL_T

	add edx,16

	mov al,dh

	stdcall Byte_To_Hex

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

	mov al,dl

	stdcall Byte_To_Hex

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

	mov [edi],dword 0x20203A20

	add edi,4

  .NEXT:

	inc esi

	cmp cx,512

	jl .PRINT

  .NULL_T:

	; NULL terminate bfDisplay

	mov [edi],byte 0

	ret

endp

; -------------------------------------------------------------------------------------

proc Print_Status

  ; print the status of the registers

	lea edi,[bfDisplay]

	mov [edi],dword "Regi"

	add edi,4

	mov [edi],dword "ster"

	add edi,4

	mov [edi],word "s:"

	add edi,2

	PRINT_CRLF

	PRINT_CRLF

	; accumulator

	mov [edi],dword "ACC "

	add edi,4

	mov [edi],word 0x203a

	add edi,2

	lea esi,[Accumulator]

	stdcall Byte_To_Ascii

	PRINT_CRLF

	; index register X

	mov [edi],dword "IRX "

	add edi,4

	mov [edi],word 0x203a

	add edi,2

	lea esi,[Index_Reg_X]

	stdcall Byte_To_Ascii

	PRINT_CRLF

	; index register y

	mov [edi],dword "IRY "

	add edi,4

	mov [edi],word 0x203a

	add edi,2

	lea esi,[Index_Reg_Y]

	stdcall Byte_To_Ascii

	PRINT_CRLF

	; stack pointer

	mov [edi],dword "SP  "

	add edi,4

	mov [edi],word 0x203a

	add edi,2

	lea esi,[Stack_Pointer]

	stdcall Byte_To_Ascii

	PRINT_CRLF

	; NZ_VC - print as binary digits

	mov [edi],dword "NVZC"

	add edi,4

	mov [edi],word 0x203a

	add edi,2

	lea esi,[NV_ZC]

	xor eax,eax

	mov al,[esi]

	mov ah,al

	; the C flag

	and al,1

	add al,48

	; the Z flag

	shr ah,1

	and ah,1

	add ah,48

	bswap eax

	mov al,[esi]

	mov ah,al

	; the N flag

	shr al,7

	and al,1

	add al,48

	; the V flag

	shr ah,6

	and ah,1

	add ah,48

	mov [edi],eax

	add edi,4

	PRINT_CRLF

	; program counter

	mov [edi],dword "PC  "

	add edi,4

	mov [edi],word 0x203a

	add edi,2

	lea esi,[Program_Counter]

	inc esi

	stdcall Byte_To_Ascii

	dec esi

	stdcall Byte_To_Ascii

	PRINT_CRLF

	; NULL terminate bfDisplay

	mov [edi],byte 0

	ret

endp

; -------------------------------------------------------------------------------------

proc Byte_To_Ascii

  ; convert a byte to 2 ASCII chars

  ; read the byte from ESI

  ; write the ASCII chars to EDI

	mov al,[esi]

	; put the low nibble into AL and the high nibble into AH

	mov ah,al

	and al,0xf

	shr ah,4

	and ah,0xf

	; convert the low nibble to an ASCII char

  .AL_09:

	cmp al,9

	jg .AL_AF

	add al,'0'

	jmp .AH_09

  .AL_AF:

	sub al,10

	add al,'A'

	; convert the high nibble to an ASCII char

  .AH_09:

	cmp ah,9

	jg .AH_AF

	add ah,'0'

	jmp .DONE

  .AH_AF:

	sub ah,10

	add ah,'A'

  .DONE:

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

	ret

endp

; -------------------------------------------------------------------------------------

proc Byte_To_Hex

  ; convert a byte to 2 hex digits

  ; read the byte from AL

  ; write the hex digits to AX

	; put the low nibble into AL and the high nibble into AH

	mov ah,al

	and al,0xf

	shr ah,4

	and ah,0xf

	; convert the low nibble to a hex digit

  .AL_09:

	cmp al,9

	jg .AL_AF

	add al,'0'

	jmp .AH_09

  .AL_AF:

	sub al,10

	add al,'A'

	; convert the high nibble to a hex digit

  .AH_09:

	cmp ah,9

	jg .AH_AF

	add ah,'0'

	jmp .DONE

  .AH_AF:

	sub ah,10

	add ah,'A'

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Set_CB_String

  ; set the combo-box string

  ; index is in CL (0-127)

  ; index 0 = pages 0-1

  ; index 1 = pages 2-3

  ; and so on

	lea edi,[cbString]

	mov [edi],dword "Page"
	add edi,4

	mov [edi],dword "s:  "
	add edi,4

	mov dl,cl

	shl dl,1

	stdcall Byte_To_Decimal

	bswap eax

	mov [edi],eax
	add edi,4

	mov [edi],byte '-'

	inc edi

	mov dl,cl

	shl dl,1

	inc dl

	stdcall Byte_To_Decimal

	bswap eax

	mov [edi],eax
	add edi,4

	mov [edi],byte 0

	ret

endp

; -------------------------------------------------------------------------------------

proc Byte_To_Decimal

  ; byte is in DL - result returned in EAX

	xor eax,eax

	; digit 4 = always zero

	mov ah,48

	; digit 3 = hundreds (0,1,2)

	mov al,48

	cmp dl,200

	jb .100

	sub dl,200

	mov al,50

	jmp .NEXT

  .100:

	cmp dl,100

	jb .NEXT

	sub dl,100

	mov al,49

  .NEXT:

	shl eax,16

	mov ah,48

	; digit 2 = tens

  .10:

	cmp dl,10

	jb .1

	sub dl,10

	inc ah

	jmp .10

  .1:

	mov al,dl

	add al,48

	ret

endp

; -------------------------------------------------------------------------------------

proc Calc_Decimal uses eax ebx

  ; up to 4 decimal digits are passed in EDX

  ; return value in DX

  ; called by proc Get_Operand_Size

	xor eax,eax

	xor ebx,ebx

	; digit 1:

	mov al,dl

	cmp al,0

	je .DONE

	sub al,'0'

	; digit 2

	shr edx,8

	cmp dl,0

	je .DONE

	sub dl,'0'

	; multiply EAX by 10

	mov ebx,eax

	shl ebx,3

	shl eax,1

	add eax,ebx

	; add the value of the digit

	xor ebx,ebx

	mov bl,dl

	add eax,ebx

	; digit 3

	shr edx,8

	cmp dl,0

	je .DONE

	sub dl,'0'

	; multiply EAX by 10

	mov ebx,eax

	shl ebx,3

	shl eax,1

	add eax,ebx

	; add the value of the digit

	xor ebx,ebx

	mov bl,dl

	add eax,ebx

	; digit 4

	shr edx,8

	cmp dl,0

	je .DONE

	sub dl,'0'

	; multiply EAX by 10

	mov ebx,eax

	shl ebx,3

	shl eax,1

	add eax,ebx

	; add the value of the digit

	xor ebx,ebx

	mov bl,dl

	add eax,ebx

  .DONE:

	mov edx,eax

	ret

endp

; -------------------------------------------------------------------------------------

proc Read_Number uses esi ebx ecx

  ; read a number from bfOperand

  ; can be binary, decimal or hex

  ; return a 2 byte value in DX

  ; called by proc Process_Labels_PsOps_1 and proc Process_Labels_PsOps_2

	xor edx,edx

	lea esi,[bfOperand]

	xor ecx,ecx

	; detect a hex number ?

	cmp [esi],byte '$'

	je .HEX

	; detect a binary number ?

	cmp [esi],byte '%'

	je .BIN

	; detect a decimal number ?

	cmp [esi],byte '!'

	je .NEXT_D

	; assume that the number is decimal:

	jmp .DEC

  .HEX:

	; hex - read a maximum of 4 hex digits

	inc esi

	mov bl,[esi]

	cmp bl,0

	je .DONE

	cmp bl,'0'

	jl .DEBUG_1

	cmp bl,'9'

	jle .ADD_09

	cmp bl,'A'

	jl .DEBUG_1

	cmp bl,'F'

	jle .ADD_AF

	jmp .DEBUG_1

  .ADD_09:

	; add the digit to EDX (0-9)

	shl edx,4

	sub bl,'0'

	or dl,bl

	jmp .NEXT_H

  .ADD_AF:

	; add the digit to EDX (A-F)

	shl edx,4

	sub bl,'A'

	add bl,10

	or dl,bl

  .NEXT_H:

	inc cx

	; read a maximum of 4 hex digits

	cmp cx,4

	jg .DEBUG_2

	jmp .HEX

  .BIN:

	; binary - read a maximum of 16 binary digits

	inc esi

	mov bl,[esi]

	cmp bl,0

	je .DONE

	shl edx,1

	cmp bl,'0'

	je .NEXT_B

	cmp bl,'1'

	jne .DEBUG_3

	or edx,1

  .NEXT_B:

	inc cx

	; read a maximum of 16 bits

	cmp cx,16

	jg .DEBUG_2

	jmp .BIN

  .DEC:

	; decimal - read a maximum of 5 decimal digits

	xor ebx,ebx

	cmp [esi],byte 0

	je .CHECK

	cmp [esi],byte '0'

	jl .DEBUG_4

	cmp [esi],byte '9'

	jg .DEBUG_4

	; multiply EDX by 10

	mov ebx,edx

	shl ebx,3

	shl edx,1

	add edx,ebx

	; add the new digit to EDX

	xor ebx,ebx

	mov bl,[esi]

	sub bl,'0'

	add edx,ebx

  .NEXT_D:

	inc esi

	inc cx

	; read a maximum of 5 decimal digits

	cmp cx,5

	jg .DEBUG_2

	jmp .DEC

  .CHECK:

	cmp edx,65536

	jb .DONE

	; decimal number is greater than a 2 byte value

	mov [Debug_Code],word 19

	jmp .ERROR

  .DEBUG_1:

	; invalid char in hex number

	mov [Debug_Code],word 20

	jmp .ERROR

  .DEBUG_2:

	; too many digits

	mov [Debug_Code],word 21

	jmp .ERROR

  .DEBUG_3:

	; invalid char in binary number

	mov [Debug_Code],word 22

	jmp .ERROR

  .DEBUG_4:

	; invalid char in decimal number

	mov [Debug_Code],word 23

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Read_Hex uses esi ebx

  ; read a hex number from bfOperand - for the HEX pseudo-op

  ; max size = 4 bytes = 8 hex digits

  ; return in EDX

  ; called by proc Process_Labels_PsOps_1 and proc Process_Labels_PsOps_2

	xor edx,edx

	lea esi,[bfOperand]

	xor ecx,ecx

  .READ:

	; read a pair of hex digits

	; BH = the high nibble

	mov bh,[esi]

	cmp bh,0

	je .1

	; BL = the low nibble

	inc esi

	mov bl,[esi]

	cmp bl,0

	je .1

  .D1:

	cmp bh,'0'

	jl .DEBUG_1

	cmp bh,'9'

	jg .AF_D1

	sub bh,'0'

	jmp .D2

  .AF_D1:

	cmp bh,'A'

	jl .DEBUG_1

	cmp bh,'F'

	jg .DEBUG_1

	sub bh,'A'

	add bh,10

  .D2:

	cmp bl,'0'

	jl .DEBUG_1

	cmp bl,'9'

	jg .AF_D2

	sub bl,'0'

	jmp .CALC

  .AF_D2:

	cmp bl,'A'

	jl .DEBUG_1

	cmp bl,'F'

	jg .DEBUG_1

	sub bl,'A'

	add bl,10

  .CALC:

	shl bh,4

	or bl,bh

	; the byte is now in BL - add to EDX

	shl edx,8

	mov dl,bl

  .NEXT:

	inc esi

	inc cx

	; read a maximum of 8 hex digits (4 bytes)

	cmp cx,4

	jg .DEBUG_2

	jmp .READ

  .DEBUG_1:

	; invalid char

	mov [Debug_Code],word 24

	jmp .ERROR

  .DEBUG_2:

	; too many digits

	mov [Debug_Code],word 25

  .ERROR:

	mov eax,0xffffffff

	jmp .DONE

	; put EDX into the correct byte order

  .1:

	cmp cx,1

	jle .DONE

  .2:
	cmp cx,2

	jg .3

	bswap edx

	shr edx,16

	jmp .DONE

  .3:

	cmp cx,3

	jg .4

	bswap edx

	shr edx,8

	jmp .DONE

  .4:

	bswap edx

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Get_Hex_Value uses ecx

  ; read up to 4 hex digits from ESI

  ; ESI is set outside of this proc

  ; return result in EAX - a 1 or 2 byte value

  ; called by proc Calc_Operand_Value

	xor eax,eax

	xor ecx,ecx

	; first char from ESI must be a valid hex digit

	cmp [esi],byte '0'

	jl .DEBUG_1

	cmp [esi],byte '9'

	jle .ADD_09

	cmp [esi],byte 'A'

	jl .DEBUG_1

	cmp [esi],byte 'F'

	jle .ADD_AF

	jmp .DEBUG_1

  .NEXT:

	; get the next hex digit

	; stop reading digits when a null, plus, minus, comma or ) is found

	inc esi

	cmp [esi],byte 0

	je .CALC

	cmp [esi],byte '+'

	je .CALC

	cmp [esi],byte '-'

	je .CALC

	cmp [esi],byte ','

	je .CALC

	cmp [esi],byte ')'

	je .CALC

	cmp [esi],byte '0'

	jl .DEBUG_1

	cmp [esi],byte '9'

	jle .ADD_09

	cmp [esi],byte 'A'

	jl .DEBUG_1

	cmp [esi],byte 'F'

	jle .ADD_AF

	jmp .DEBUG_1

  .ADD_09:

	; add the digit to EAX (0-9)

	shl eax,8

	mov al,[esi]

	sub al,'0'

	inc cx

	cmp cx,4

	jg .DEBUG_2

	jmp .NEXT

  .ADD_AF:

	; add the digit to EAX (A-F)

	shl eax,8

	mov al,[esi]

	sub al,'A'

	add al,10

	inc cx

	cmp cx,4

	jg .DEBUG_2

	jmp .NEXT

  .CALC:

	; convert to a 2 byte value

	shl ah,4

	or al,ah

	mov ecx,eax

	shr ecx,16

	shl ch,4

	or cl,ch

	mov ah,cl

	and eax,0xffff

	jmp .DONE

  .DEBUG_1:

	; invalid char

	mov [Debug_Code],word 26

	jmp .ERROR

  .DEBUG_2:

	; too many digits (max = 4)

	mov [Debug_Code],word 27

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Get_Dec_Value uses ebx ecx edx

  ; read up to 5 decimal digits from ESI

  ; value must be less than or equal to 65536

  ; ESI is set outside of this proc

  ; return result in EAX - a 1 or 2 byte value

  ; called by proc Calc_Operand_Value

	xor eax,eax

	xor edx,edx

  .DIGIT_1:

	; the first char from ESI must be a decimal digit

	cmp [esi],byte '0'

	jl .DEBUG_1

	cmp [esi],byte '9'

	jg .DEBUG_1

	mov dl,[esi]

	sub dl,'0'

	mov eax,edx

	mov ecx,1

 .NEXT:

	; get the next decimal digit

	; stop reading digits when a null, plus, minus, comma or ) is found

	inc esi

	cmp [esi],byte 0

	je .CHECK

	cmp [esi],byte '+'

	je .CHECK

	cmp [esi],byte '-'

	je .CHECK

	cmp [esi],byte ','

	je .CHECK

	cmp [esi],byte ')'

	je .CHECK

	cmp [esi],byte '0'

	jl .DEBUG_1

	cmp [esi],byte '9'

	jg .DEBUG_1

  .ADD_D:

	; add the digit to EAX

	mov dl,[esi]

	sub dl,'0'

	; multiply EAX by 10

	mov ebx,eax

	shl ebx,3

	shl eax,1

	add eax,ebx

	; add the new digit

	add eax,edx

	; read up to 5 digits

	inc cl

	cmp cl,5

	jg .DEBUG_2

	jmp .NEXT

  .CHECK:

	; is the decimal number 2 bytes or less ?

	cmp eax,65535

	ja .DEBUG_3

	jmp .DONE

  .DEBUG_1:

	; invalid char

	mov [Debug_Code],word 28

	jmp .ERROR

  .DEBUG_2:

	; too many digits

	mov [Debug_Code],word 29

	jmp .ERROR

  .DEBUG_3:

	; result is greater than 2 bytes

	mov [Debug_Code],word 30

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Get_Bin_Value uses ebx

  ; read up to 16 binary digits from ESI

  ; ESI is set outside of this proc

  ; return result in EAX - a 1 or 2 byte value

  ; called by proc Calc_Operand_Value

	xor eax,eax

	xor ecx,ecx

	; first char from ESI must be a valid binary digit

	cmp [esi],byte '0'

	jl .DEBUG_1

	cmp [esi],byte '1'

	jle .ADD_BIN

	jmp .DEBUG_1

  .NEXT:

	; get the next binary digit

	; stop reading digits when a null, plus, minus, comma or ) is found

	inc esi

	cmp [esi],byte 0

	je .DONE

	cmp [esi],byte '+'

	je .DONE

	cmp [esi],byte '-'

	je .DONE

	cmp [esi],byte ','

	je .DONE

	cmp [esi],byte ')'

	je .DONE

	cmp [esi],byte '0'

	jl .DEBUG_1

	cmp [esi],byte '1'

	jle .ADD_BIN

	; an invalid char has been found:

	jmp .DEBUG_1

  .ADD_BIN:

	; add the digit to EAX

	shl eax,1

	mov bl,[esi]

	sub bl,'0'

	or al,bl

	inc cx

	cmp cx,16

	jg .DEBUG_2

	jmp .NEXT

  .DEBUG_1:

	; invalid char

	mov [Debug_Code],word 39

	jmp .ERROR

  .DEBUG_2:

	; too many digits (max = 16)

	mov [Debug_Code],word 40

  .ERROR:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Store_Hex uses edi ebx

  ; store the bytes passed in EDX in memory - up to 4 bytes

  ; CL gives the number of bytes to store

	lea edi,[Main_Memory]

	xor ebx,ebx

	mov bx,[Location_Counter]

	; byte 1

	jcxz .DONE

	mov [edi+ebx],dl

	inc word [Location_Counter]

	dec cx

	; byte 2

	jcxz .DONE

	inc bx

	shr edx,8

	mov [edi+ebx],dl

	inc word [Location_Counter]

	dec cx

	; byte 3

	jcxz .DONE

	inc bx

	shr edx,8

	mov [edi+ebx],dl

	inc word [Location_Counter]

	dec cx

	; byte 4

	jcxz .DONE

	inc bx

	shr edx,8

	mov [edi+ebx],dl

	inc word [Location_Counter]

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Char_To_Upper

  ; if the char in AL is lower case - convert to upper case

	cmp al,97

	jl .DONE

	cmp al,122

	jg .DONE

	sub al,32

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Increment_Symbol_Pointer

	; increment the symbol pointer

	xor eax,eax

	; increment by adding 16 bytes

	add [pSymbol_Table],16

	lea edx,[Main_Memory]

	add edx,65536

	cmp edx,[pSymbol_Table]

	jg .DONE

	; error - the symbol pointer points past the end of the 6502's memory

	mov eax,0xffffffff

	mov [Debug_Code],word 11

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Reset_Symbol_Pointer

  ; reset the symbol table pointer

  ; symbol table  = pages 252, 253, 254, 255

	lea edx,[Main_Memory]

	; symbol table starts on page 252

	add edx,64512

	mov [pSymbol_Table],edx

	ret

endp

; -------------------------------------------------------------------------------------

proc Print_Symbol_Table uses ebx

  ; print the symbol table to bfDisplay

	lea edi,[bfDisplay]

	lea esi,[Main_Memory]

	; symbol table starts on page 252

	add esi,64512

	mov edx,64512

  .ROW:

	; exit if the table entry is NULL

	cmp [esi],byte 0

	je .DONE

	; print the address of the table entry (in DX)

	mov al,dh

	stdcall Byte_To_Hex

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

	mov al,dl

	stdcall Byte_To_Hex

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

	mov [edi],dword 0x20203A20

	add edi,4

	mov [edi],word 0x2020

	add edi,2

	xor ecx,ecx

  .PRINT:

	; print the symbol - up to 14 chars

	mov al,[esi]

	cmp al,0

	jne .SKIP

	mov al,32

  .SKIP:

	mov [edi],al

	inc esi

	inc edi

	inc cx

	cmp cx,14

	jl .PRINT

	mov [edi],dword 0x20202020

	add edi,4

	mov [edi],byte '$'

	inc edi

	; print the address pointed to by the symbol

	inc esi

	stdcall Byte_To_Ascii

	dec esi

	stdcall Byte_To_Ascii

	add esi,2

	PRINT_CRLF

	add edx,16

	jmp .ROW

  .DONE:

	mov [edi],byte 0

	ret

endp

; -------------------------------------------------------------------------------------

proc Print_Compile_Error

  ; if the compile fails, print an error message

	lea edi,[bfOutput]

	mov [edi],dword "Comp"

	add edi,4

	mov [edi],dword "ile "

	add edi,4

	mov [edi],dword "Erro"

	add edi,4

	mov [edi],dword "r in"

	add edi,4

	mov [edi],dword " the"

	add edi,4

	mov [edi],dword " lin"

	add edi,4

	mov [edi],dword "e:  "

	add edi,4

	mov [edi],dword 0x0A0D0A0D

	add edi,4

	lea esi,[bfCurrentLine]

	; print the current line

  .COPY:

	mov al,[esi]

	cmp al,0

	je .ERR

	mov [edi],al

	inc esi

	inc edi

	jmp .COPY

  .ERR:

	; check the debug code to determine which error message to print

	mov [edi],dword 0x0A0D0A0D

	add edi,4

	mov al,byte [Debug_Code]

	cmp al,1

	je .ERR_1

	cmp al,2

	je .ERR_2

	cmp al,3

	je .ERR_3

	cmp al,4

	je .ERR_4

	cmp al,5

	je .ERR_5

	cmp al,6

	je .ERR_6

	cmp al,7

	je .ERR_7

	cmp al,8

	je .ERR_8

	cmp al,9

	je .ERR_9

	cmp al,10

	je .ERR_10

	cmp al,11

	je .ERR_11

	cmp al,12

	je .ERR_12

	cmp al,13

	je .ERR_13

	cmp al,14

	je .ERR_14

	cmp al,15

	je .ERR_15

	cmp al,16

	je .ERR_16

	cmp al,17

	je .ERR_17

	cmp al,18

	je .ERR_18

	cmp al,19

	je .ERR_19

	cmp al,20

	je .ERR_20

	cmp al,21

	je .ERR_21

	cmp al,22

	je .ERR_22

	cmp al,23

	je .ERR_23

	cmp al,24

	je .ERR_24

	cmp al,25

	je .ERR_25

	cmp al,26

	je .ERR_26

	cmp al,27

	je .ERR_27

	cmp al,28

	je .ERR_28

	cmp al,29

	je .ERR_29

	cmp al,30

	je .ERR_30

	cmp al,31

	je .ERR_31

	cmp al,32

	je .ERR_32

	cmp al,33

	je .ERR_33

	cmp al,34

	je .ERR_34

	cmp al,35

	je .ERR_35

	cmp al,36

	je .ERR_36

	cmp al,37

	je .ERR_37

	cmp al,39

	je .ERR_39

	cmp al,40

	je .ERR_40

	cmp al,41

	je .ERR_41

	cmp al,43

	je .ERR_43

  .ERR_0:

	lea esi,[szErrMessage_0]

	jmp .PRINT

  .ERR_1:

	lea esi,[szErrMessage_1]

	jmp .PRINT

  .ERR_2:

	lea esi,[szErrMessage_2]

	jmp .PRINT

  .ERR_3:

	lea esi,[szErrMessage_3]

	jmp .PRINT

  .ERR_4:

	lea esi,[szErrMessage_4]

	jmp .PRINT

  .ERR_5:

	lea esi,[szErrMessage_5]

	jmp .PRINT

  .ERR_6:

	lea esi,[szErrMessage_6]

	jmp .PRINT

  .ERR_7:

	lea esi,[szErrMessage_7]

	jmp .PRINT

  .ERR_8:

	lea esi,[szErrMessage_8]

	jmp .PRINT

  .ERR_9:

	lea esi,[szErrMessage_9]

	jmp .PRINT

  .ERR_10:

	lea esi,[szErrMessage_10]

	jmp .PRINT

  .ERR_11:

	lea esi,[szErrMessage_11]

	jmp .PRINT

  .ERR_12:

	lea esi,[szErrMessage_12]

	jmp .PRINT

  .ERR_13:

	lea esi,[szErrMessage_13]

	jmp .PRINT

  .ERR_14:

	lea esi,[szErrMessage_14]

	jmp .PRINT

  .ERR_15:

	lea esi,[szErrMessage_15]

	jmp .PRINT

  .ERR_16:

	lea esi,[szErrMessage_16]

	jmp .PRINT

  .ERR_17:

	lea esi,[szErrMessage_17]

	jmp .PRINT

  .ERR_18:

	lea esi,[szErrMessage_18]

	jmp .PRINT

  .ERR_19:

	lea esi,[szErrMessage_19]

	jmp .PRINT

  .ERR_20:

	lea esi,[szErrMessage_20]

	jmp .PRINT

  .ERR_21:

	lea esi,[szErrMessage_21]

	jmp .PRINT

  .ERR_22:

	lea esi,[szErrMessage_22]

	jmp .PRINT

  .ERR_23:

	lea esi,[szErrMessage_23]

	jmp .PRINT

  .ERR_24:

	lea esi,[szErrMessage_24]

	jmp .PRINT

  .ERR_25:

	lea esi,[szErrMessage_25]

	jmp .PRINT

  .ERR_26:

	lea esi,[szErrMessage_26]

	jmp .PRINT

  .ERR_27:

	lea esi,[szErrMessage_27]

	jmp .PRINT

  .ERR_28:

	lea esi,[szErrMessage_28]

	jmp .PRINT

  .ERR_29:

	lea esi,[szErrMessage_29]

	jmp .PRINT

  .ERR_30:

	lea esi,[szErrMessage_30]

	jmp .PRINT

  .ERR_31:

	lea esi,[szErrMessage_31]

	jmp .PRINT

  .ERR_32:

	lea esi,[szErrMessage_32]

	jmp .PRINT

  .ERR_33:

	lea esi,[szErrMessage_33]

	jmp .PRINT

  .ERR_34:

	lea esi,[szErrMessage_34]

	jmp .PRINT

  .ERR_35:

	lea esi,[szErrMessage_35]

	jmp .PRINT

  .ERR_36:

	lea esi,[szErrMessage_36]

	jmp .PRINT

  .ERR_37:

	lea esi,[szErrMessage_37]

	jmp .PRINT

  .ERR_39:

	lea esi,[szErrMessage_39]

	jmp .PRINT

  .ERR_40:

	lea esi,[szErrMessage_40]

	jmp .PRINT

  .ERR_41:

	lea esi,[szErrMessage_41]

	jmp .PRINT

  .ERR_43:

	lea esi,[szErrMessage_43]

  .PRINT:

	; print the error message

	mov al,[esi]

	cmp al,0

	je .DONE

	mov [edi],al

	inc esi

	inc edi

	jmp .PRINT

  .DONE:

	mov [edi],dword 0x0A0D0A0D

	add edi,4

	mov [edi],dword "Debu"

	add edi,4

	mov [edi],dword "g Co"

	add edi,4

	mov [edi],dword "de: "

	add edi,4

	mov dl,byte [Debug_Code]

	stdcall Byte_To_Decimal

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

	mov [edi],byte 0

	ret

endp

; -------------------------------------------------------------------------------------

proc Print_Exe_Error

  ; if an instruction fails to execute, print an error message

	lea edi,[bfDisplay]

	lea esi,[szErrMessage_38]

  .PRINT:

	; print the error message

	mov al,[esi]

	cmp al,0

	je .DONE

	mov [edi],al

	inc esi

	inc edi

	jmp .PRINT

  .DONE:

	mov [edi],dword 0x0A0D0A0D

	add edi,4

	mov [edi],dword "Prog"

	add edi,4

	mov [edi],dword "ram "

	add edi,4

	mov [edi],dword "Coun"

	add edi,4

	mov [edi],dword "ter:"

	add edi,4

	mov [edi],byte 32

	inc edi

	mov ax,word [Exe_Info]

	shr ax,8

	stdcall Byte_To_Hex

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

	mov ax,word [Exe_Info]

	stdcall Byte_To_Hex

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

	mov [edi],dword 0x0A0D0A0D

	add edi,4

	mov [edi],dword "Inst"

	add edi,4

	mov [edi],dword "ruct"

	add edi,4

	mov [edi],dword "ion "

	add edi,4

	mov [edi],dword "Byte"

	add edi,4

	mov [edi],word ": "

	add edi,2

	mov al,byte [Debug_Code]

	stdcall Byte_To_Hex

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

	mov [edi],byte 0

	ret

endp

; -------------------------------------------------------------------------------------

proc Reset_Output uses edi

  ; the compile result is written to bfOutput:

  ; the value of the location counter, the bytes that were assembled and the input line

  ; pOutput points to the current position within bfOutput - reset pOutput

	mov dword [pOutput],0

	lea edi,[bfOutput]

	mov [edi],byte 0

	ret

endp

; -------------------------------------------------------------------------------------

proc Write_LC_To_Output uses edi ecx edx

  ; before assembling the next line, write the value of the location counter to output

	lea edi,[bfOutput]

	mov edx,[pOutput]

	cmp edx,32600

	jge .ERROR

	mov cx,word [Location_Counter]

	; write the location counter (in CX)

	mov al,ch

	stdcall Byte_To_Hex

	mov [edi+edx],ah

	inc edx

	mov [edi+edx],al

	inc edx

	mov al,cl

	stdcall Byte_To_Hex

	mov [edi+edx],ah

	inc edx

	mov [edi+edx],al

	inc edx

	mov [edi+edx],byte 9

	inc edx

	; null terminate

	mov [edi+edx],byte 0

	jmp .DONE


  .ERROR:

	mov [Debug_Code],word 43

	mov eax,0xffffffff

  .DONE:

	; update pOutput

	mov dword [pOutput],edx

	ret

endp

; -------------------------------------------------------------------------------------

proc Write_Asm_To_Output uses esi edi ebx edx

  ; after the current line has been assembled, write the result to bfOutput:

  ; the assembled bytes

  ; the text of each field in the current line

	locals

	  nBytes db 0

	endl

	lea edi,[bfOutput]

	mov edx,[pOutput]

	cmp edx,32600

	jge .ERROR

	; write the bytes that were assembled

	mov ebx,[Asm_Bytes]

	bswap ebx

	mov [nBytes],bl

	; if there was just a label on the line:

	cmp byte [nBytes],0

	je .PAD_0

	bswap ebx

	; write the op code byte

	mov al,bl

	stdcall Byte_To_Hex

	mov [edi+edx],ah

	inc edx

	mov [edi+edx],al

	inc edx

	mov [edi+edx],byte 32

	cmp byte [nBytes],1

	je .PAD_1

	inc edx

	; write the first data byte (if any)

	shr ebx,8

	mov al,bl

	stdcall Byte_To_Hex

	mov [edi+edx],ah

	inc edx

	mov [edi+edx],al

	inc edx

	mov [edi+edx],byte 32

	cmp byte [nBytes],2

	je .PAD_2

	inc edx

	; write the second data byte (if any)

	mov al,bh

	stdcall Byte_To_Hex

	mov [edi+edx],ah

	inc edx

	mov [edi+edx],al

	inc edx

	jmp .TEXT

  .PAD_0:

	mov [edi+edx],word "--"

	add edx,2

  .PAD_1:

	mov [edi+edx],byte 32

	inc edx

	mov [edi+edx],word "--"

	add edx,2

  .PAD_2:

	mov [edi+edx],byte 32

	inc edx

	mov [edi+edx],word "--"

	add edx,2

  .TEXT:

	mov [edi+edx],byte 9

	inc edx

	; write the bfLabel, bfMnemonic and bfOperand fields

	lea esi,[bfLabel]

  .COPY_L:

	mov al,[esi]

	cmp al,0

	je .COPY_M

	mov [edi+edx],al

	inc edx

	inc esi

	jmp .COPY_L

  .COPY_M:

	mov [edi+edx],byte 32

	inc edx

	lea esi,[bfMnemonic]

	; 1st letter

	mov al,[esi]

	cmp al,0

	je .NEXT

	mov [edi+edx],al

	inc edx

	; 2nd letter

	mov al,[esi+1]

	cmp al,0

	je .NEXT

	mov [edi+edx],al

	inc edx

	; 3rd letter

	mov al,[esi+2]

	cmp al,0

	je .NEXT

	mov [edi+edx],al

	inc edx

  .NEXT:

	mov [edi+edx],byte 32

	inc edx

	lea esi,[bfOperand]

  .COPY_OP:

	mov al,[esi]

	cmp al,0

	je .LAST

	mov [edi+edx],al

	inc edx

	inc esi

	jmp .COPY_OP

  .LAST:

	mov [edi+edx],byte 13

	inc edx

	mov [edi+edx],byte 10

	inc edx

	; null terminate

	mov [edi+edx],byte 0

	jmp .DONE

  .ERROR:

	mov [Debug_Code],word 43

	mov eax,0xffffffff

  .DONE:

	; update pOutput

	mov dword [pOutput],edx

	ret

endp

; -------------------------------------------------------------------------------------

proc Write_Line_To_Output uses esi edi ebx edx

  ; when the current line contains an ADR, DBY, BYT, HBY, EQU, EPZ, DFS, HEX, ORG pseudo-op

  ; call this function (in pass 2)

  ; to write the text of each field in the current line to bfOutput

	lea edi,[bfOutput]

	mov edx,[pOutput]

	cmp edx,32600

	jge .ERROR

	; the pseudo-ops emit no assembly code bytes, so these fields will be blank

	mov [edi+edx],word "--"

	add edx,2

	mov [edi+edx],byte 32

	inc edx

	mov [edi+edx],word "--"

	add edx,2

	mov [edi+edx],byte 32

	inc edx

	mov [edi+edx],word "--"

	add edx,2

	mov [edi+edx],byte 32

	inc edx

  .TEXT:

	mov [edi+edx],byte 9

	inc edx

	; write the bfLabel, bfMnemonic and bfOperand fields

	lea esi,[bfLabel]

  .COPY_L:

	mov al,[esi]

	cmp al,0

	je .COPY_M

	mov [edi+edx],al

	inc edx

	inc esi

	jmp .COPY_L

  .COPY_M:

	mov [edi+edx],byte 32

	inc edx

	lea esi,[bfMnemonic]

	; 1st letter

	mov al,[esi]

	cmp al,0

	je .NEXT

	mov [edi+edx],al

	inc edx

	; 2nd letter

	mov al,[esi+1]

	cmp al,0

	je .NEXT

	mov [edi+edx],al

	inc edx

	; 3rd letter

	mov al,[esi+2]

	cmp al,0

	je .NEXT

	mov [edi+edx],al

	inc edx

  .NEXT:

	mov [edi+edx],byte 32

	inc edx

	lea esi,[bfOperand]

  .COPY_OP:

	mov al,[esi]

	cmp al,0

	je .LAST

	mov [edi+edx],al

	inc edx

	inc esi

	jmp .COPY_OP

  .LAST:

	mov [edi+edx],byte 13

	inc edx

	mov [edi+edx],byte 10

	inc edx

	; null terminate

	mov [edi+edx],byte 0

	jmp .DONE

  .ERROR:

	mov [Debug_Code],word 43

	mov eax,0xffffffff

  .DONE:

	; update pOutput

	mov dword [pOutput],edx

	ret

endp

; -------------------------------------------------------------------------------------

proc Print_Last_Exe_Info uses esi edi

  ; print the details about the last instruction that was executed

  ; from the Exe_Info structure:

  ; ================================================

  ; bytes 0,1 = Program Counter

  ; bytes 2,3,4 = Mnemonic

  ; byte 5 = addressing mode

  ; bytes 6,7 = target address

  ; bytes 8,9,A,B = dword at target address

  ; ================================================

  ; addressing modes (byte 5):

  ; 0 = accumulator

  ; 1 = implied

  ; 2 = relative

  ; 3 = immediate

  ; 4 = absolute

  ; 5 = zero page

  ; 6 = a,x

  ; 7 = a,y

  ; 8 = zp,x

  ; 9 = zp,y

  ; 10 = (zp,x)

  ; 11 = (zp),y

  ; 12 = (a)

  ; ================================================

	lea esi,[Exe_Info]

	lea edi,[bfDisplay]

	mov [edi],dword "Last"

	add edi,4

	mov [edi],dword " Ins"

	add edi,4

	mov [edi],dword "truc"

	add edi,4

	mov [edi],dword "tion"

	add edi,4

	mov [edi],dword " Exe"

	add edi,4

	mov [edi],dword "cute"

	add edi,4

	mov [edi],dword "d = "

	add edi,4

	; print the program counter

	mov al,[esi+1]

	stdcall Byte_To_Hex

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

	mov al,[esi]

	stdcall Byte_To_Hex

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

	mov [edi],byte 32

	inc edi

	; print the mnemonic

	mov al,[esi+2]

	mov [edi],al

	inc edi

	mov al,[esi+3]

	mov [edi],al

	inc edi

	mov al,[esi+4]

	mov [edi],al

	inc edi

	PRINT_CRLF

	PRINT_CRLF

	; print the addressing mode

	mov [edi],dword "Addr"

	add edi,4

	mov [edi],dword "essi"

	add edi,4

	mov [edi],dword "ng M"

	add edi,4

	mov [edi],dword "ode "

	add edi,4

	mov [edi],dword "= "

	add edi,2

	; get the addressing mode

	mov al,[esi+5]

	cmp al,0

	je .ACC

	cmp al,1

	je .IMP

	cmp al,2

	je .REL

	cmp al,3

	je .IMM

	cmp al,4

	je .ABS

	cmp al,5

	je .ZP

	cmp al,6

	je .AX

	cmp al,7

	je .AY

	cmp al,8

	je .ZPX

	cmp al,9

	je .ZPY

	cmp al,10

	je .ZPIX

	cmp al,11

	je .ZPIY

	cmp al,12

	je .IND_A

	jmp .UN

  .ACC:

	mov [edi],dword "Accu"

	add edi,4

	mov [edi],dword "mula"

	add edi,4

	mov [edi],dword "tor "

	add edi,4

	jmp .DONE

  .IMP:

	mov [edi],dword "Impl"

	add edi,4

	mov [edi],dword "ied "

	add edi,4

	jmp .DONE

  .REL:

	mov [edi],dword "Rela"

	add edi,4

	mov [edi],dword "tive"

	add edi,4

	jmp .DONE

  .IMM:

	mov [edi],dword "Imme"

	add edi,4

	mov [edi],dword "diat"

	add edi,4

	mov [edi],word "e "

	add edi,2

	PRINT_CRLF

	PRINT_CRLF

	mov [edi],dword "Byte"

	add edi,4

	mov [edi],word " ="

	add edi,2

	mov [edi],byte 32

	inc edi

	mov al,[esi+8]

	stdcall Byte_To_Hex

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

	jmp .DONE

  .ABS:

	mov [edi],dword "Abso"

	add edi,4

	mov [edi],dword "lute"

	add edi,4

	jmp .TA

  .ZP:

	mov [edi],dword "Zero"

	add edi,4

	mov [edi],dword " Pag"

	add edi,4

	mov [edi],word "e "

	add edi,2

	jmp .TA

  .AX:

	mov [edi],dword "a,x "

	add edi,4

	jmp .TA

  .AY:

	mov [edi],dword "a,y "

	add edi,4

	jmp .TA

  .ZPX:

	mov [edi],dword "zp,x"

	add edi,4

	jmp .TA

  .ZPY:

	mov [edi],dword "zp,y"

	add edi,4

	jmp .TA

  .ZPIX:

	mov [edi],dword "(zp,"

	add edi,4

	mov [edi],word "x)"

	add edi,2

	jmp .TA

  .ZPIY:

	mov [edi],dword "(zp)"

	add edi,4

	mov [edi],word ",y"

	add edi,2

	jmp .TA

  .IND_A:

	mov [edi],dword "(a) "

	add edi,4

	jmp .TA

  .UN:

	mov [edi],dword "Unkn"

	add edi,4

	mov [edi],dword "own "

	add edi,4

	jmp .DONE

  .TA:

	PRINT_CRLF

	PRINT_CRLF

	mov [edi],dword "Targ"

	add edi,4

	mov [edi],dword "et A"

	add edi,4

	mov [edi],dword "ddre"

	add edi,4

	mov [edi],dword "ss ="

	add edi,4

	mov [edi],byte 32

	inc edi

	mov al,[esi+7]

	stdcall Byte_To_Hex

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

	mov al,[esi+6]

	stdcall Byte_To_Hex

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

	PRINT_CRLF

	PRINT_CRLF

  .DW:

	; print the 4 bytes in memory starting from the target address

	stdcall Get_Exe_Info_89

	mov [edi],dword "Byte"

	add edi,4

	mov [edi],dword "s(Ad"

	add edi,4

	mov [edi],dword "dres"

	add edi,4

	mov [edi],dword "s) ="

	add edi,4

	mov [edi],byte 32

	inc edi

	mov al,[esi+8]

	stdcall Byte_To_Hex

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

	mov [edi],byte 32

	inc edi

	mov al,[esi+9]

	stdcall Byte_To_Hex

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

	mov [edi],byte 32

	inc edi

	mov al,[esi+10]

	stdcall Byte_To_Hex

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

	mov [edi],byte 32

	inc edi

	mov al,[esi+11]

	stdcall Byte_To_Hex

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

  .DONE:

	mov [edi],byte 0

	ret

endp

; -------------------------------------------------------------------------------------

proc Get_Exe_Info_89 uses esi

  ; get the dword at the target address

	lea esi,[Main_Memory]

	xor edx,edx

	mov dx,word [Exe_Info_67]

	mov edx,[esi+edx]

	mov dword [Exe_Info_89],edx

	ret

endp

; -------------------------------------------------------------------------------------

proc Reset_Exe_Info uses edi

	; clear the Exe_Info data structure

	lea edi,[Exe_Info]

	mov [edi],dword 0

	mov [edi+4],dword 0

	mov [edi+8],dword 0

	ret

endp

; -------------------------------------------------------------------------------------

proc Add_To_Watch

  ; add a symbol or address to the watch

  ; input formats:

  ; (1) $hhhh,nbytes

  ; (2) Symbol,nbytes

	locals

	  addr dw 0

	endl

	lea esi,[bfDisplay]

	; convert all letters to uppercase

  .UP:

	mov al,[esi]

	stdcall Char_To_Upper

	mov [esi],al

	inc esi

	cmp al,0

	jne .UP

	lea esi,[bfDisplay]

	; read the input

	cmp [esi],byte '$'

	je .ADDR

	cmp [esi],byte 'A'

	jl .ERROR

	cmp [esi],byte 'Z'

	jle .SYMB

  .ERROR:

	mov eax,0xffffffff

	jmp .DONE

  .ADDR:

	; read a hexadecimal address

	inc esi

	stdcall Get_Hex_Value

	cmp eax,0xffffffff

	je .DONE

	mov word [addr],ax

	jmp .N_BYTES

  .SYMB:

	; read a symbol

	lea edi,[bfSymbol]

  .COPY:

	mov al,[esi]

	cmp al,','

	je .NULL_T

	cmp al,0

	je .ERROR

	mov [edi],al

	inc esi

	inc edi

	jmp .COPY

  .NULL_T:

	mov [edi],byte 0

	stdcall Find_Symbol

	cmp eax,0xffffffff

	je .DONE

	mov word [addr],ax

  .N_BYTES:

	; read the number of bytes

	inc esi

	stdcall Get_Dec_Value

	cmp eax,0xffffffff

	je .DONE

	cmp ax,256

	jle .NEXT

	mov ax,256

  .NEXT:

	mov dx,ax

	shl edx,16

	mov dx,word [addr]

	; add to the watch array - passed in EDX

	stdcall Add_To_Watch_Arr

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Add_To_Watch_Arr uses edi ecx

  ; add an entry to the watch array

  ; data passed in EDX:

  ; bytes 0,1 = address

  ; bytes 2,3 = number of bytes to display

  ; Watch_Arr has room for 12 entries

  ; W_Arr_Index gives the index (0-11)

  ; W_Arr_Index wraps back to zero once the watch array is full

	lea edi,[Watch_Arr]

	xor ecx,ecx

	mov cl,[W_Arr_Index]

	shl ecx,2

	add edi,ecx

	mov [edi],edx

	inc byte [W_Arr_Index]

	cmp byte [W_Arr_Index],12

	jl .DONE

	mov byte [W_Arr_Index],0

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Reset_Watch_Arr

  ; reset the watch array

	mov byte [W_Arr_Index],0

	lea edi,[Watch_Arr]

	xor ecx,ecx

  .CLEAR:

	mov [edi],dword 0

	add edi,4

	inc cx

	cmp cx,12

	jl .CLEAR

	ret

endp

; -------------------------------------------------------------------------------------

proc Find_Symbol uses esi edi ecx edx

  ; find the current symbol in the symbol table

  ; get the address of the entry within the main memory

  ; return the result in AX

	lea esi,[bfSymbol]

	lea edi,[Main_Memory]

	mov edx,64512

	add edi,edx

	; check if there are any symbols

	cmp [edi],byte 0

	je .NO_MATCH

	xor ecx,ecx

  .TEST:

	; test bfSymbol against the current entry in the symbol table

	mov al,[esi+ecx]

	cmp al,[edi+ecx]

	jne .NEXT

	cmp al,0

	je .MATCH

	inc cx

	cmp cx,14

	jl .TEST

  .NEXT:

	xor ecx,ecx

	add edi,16

	add edx,16

	cmp [edi],byte 0

	je .NO_MATCH

	jmp .TEST

  .MATCH:

	; copy the result to EAX

	mov eax,edx

	jmp .DONE

  .NO_MATCH:

	mov eax,0xffffffff

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Print_Watch_Error

  ; bad input - could not add to the watch

  ; print an error message

	lea edi,[bfDisplay]

	lea esi,[szErrMessage_42]

  .PRINT:

	mov al,[esi]

	mov [edi],al

	cmp al,0

	je .DONE

	inc esi

	inc edi

	jmp .PRINT

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Print_Watch

  ; print the watch array

	lea esi,[Watch_Arr]

	lea edi,[bfDisplay]

	locals

	  index db 0

	  count db 0

	endl

  .W_ARR:

	; read the next entry - exit if zero

	mov edx,[esi]

	cmp edx,0

	je .DONE

	cmp dx,64512

	jb .ADDR

  .SYMB:

	; DX points to an entry in the symbol table

	; get the symbol

	lea ebx,[Main_Memory]

	xor ecx,ecx

	mov cx,dx

	; set EBX to point to the table entry

	add ebx,ecx

  .COPY:

	; print out the symbol

	mov al,[ebx]

	cmp al,0

	je .NEXT

	mov [edi],al

	inc edi

	inc ebx

	jmp .COPY

  .NEXT:

	mov [edi],byte ":"

	inc edi

	PRINT_CRLF

	PRINT_CRLF

	; adjust DX so that it points to the memory address pointed to by the symbol

	lea ebx,[Main_Memory]

	xor ecx,ecx

	mov cx,dx

	add ebx,ecx

	; the last 2 bytes of the 16 byte table entry holds the address

	add bx,14

	; adjust DX

	mov dx,[ebx]

	jmp .BYTES

  .ADDR:

	; print out the address

	mov al,dh

	stdcall Byte_To_Hex

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

	mov al,dl

	stdcall Byte_To_Hex

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

	mov [edi],byte ":"

	inc edi

	PRINT_CRLF

	PRINT_CRLF

  .BYTES:

	; print the bytes at the memory address

	lea ebx,[Main_Memory]

	xor ecx,ecx

	mov cx,dx

	add ebx,ecx

	mov ecx,edx

	shr ecx,16

	mov byte [count],0

  .LOOP:

	mov al,[ebx]

	stdcall Byte_To_Hex

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

	mov [edi],byte 32

	inc edi

	inc ebx

	inc byte [count]

	cmp byte [count],16

	jl .SKIP

	; print a CRLF for every 16 bytes printed

	mov byte [count],0

	PRINT_CRLF

  .SKIP:

	dec cx

	cmp cx,0

	jg .LOOP

	PRINT_CRLF

	PRINT_CRLF

	; if the index reaches 12 the entire watch array has been printed

	inc byte [index]

	cmp byte [index],12

	jge .DONE

	add esi,4

	; jump to read the next entry

	jmp .W_ARR

  .DONE:

	mov [edi],byte 0

	ret

endp

; -------------------------------------------------------------------------------------

proc Init_ASC

  ; initialise the message that is displayed in the ASCII input/output window

	lea edi,[bfDisplay]

	mov [edi],dword 0x65746E45

	add edi,4

	mov [edi],dword 0x6E612072

	add edi,4

	mov [edi],dword 0x63734120

	add edi,4

	mov [edi],dword 0x74206969

	add edi,4

	mov [edi],dword 0x20747865

	add edi,4

	mov [edi],dword 0x69727473

	add edi,4

	mov [edi],dword 0x6820676E

	add edi,4

	mov [edi],dword 0x20657265

	add edi,4

	mov [edi],dword 0x20646E61

	add edi,4

	mov [edi],dword 0x73657270

	add edi,4

	mov [edi],dword 0x4C5B2073

	add edi,4

	mov [edi],dword 0x2064616F

	add edi,4

	mov [edi],dword 0x49435341

	add edi,4

	mov [edi],dword 0x5D49

	add edi,2

	mov [edi],byte 0

	ret

endp

; -------------------------------------------------------------------------------------

proc Load_ASC

  ; read an ascii string from the ASCII input/output edit control

  ; read a maximum of 1024 chars

  ; load into main memory: pages 248, 249, 250, 251

  ; page 248 : byte offset = 63488

	lea esi,[bfDisplay]

	lea edi,[Main_Memory]

	add edi,63488

	xor ecx,ecx

  .LOAD:

	; load up to 1024 bytes

	mov al,[esi]

	cmp al,0

	je .CLEAR

	; filter out CRLF

	cmp al,13

	je .SKIP

	cmp al,10

	je .SKIP

	mov [edi],al

	inc edi

	inc cx

  .SKIP:

	inc esi

	cmp cx,1024

	jb .LOAD

  .CLEAR:

	; clear any previous data from the rest of the buffer

	mov [edi],byte 0

	inc edi

	inc cx

	cmp cx,1024

	jb .CLEAR

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Print_ASC

  ; print the contents of pages 248, 249, 250, 251 to bfDisplay

	locals

	  count_1 db 0
	  count_2 db 0

	endl

	lea esi,[Main_Memory]

	add esi,63488

	lea edi,[bfDisplay]

	xor ecx,ecx

	mov edx,63488

  .ROW:

	; print the address of the row (in DX)

	mov al,dh

	stdcall Byte_To_Hex

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

	mov al,dl

	stdcall Byte_To_Hex

	mov [edi],ah

	inc edi

	mov [edi],al

	inc edi

	mov [edi],dword 0x20203A20

	add edi,4

  .PRINT:

	; print a char

	mov al,[esi]

	; printable chars have ascii values from 32 to 126

	; replace non-printing chars with a space

	cmp al,31

	ja .SKIP

  .SPC:

	mov al,32

  .SKIP:

	cmp al,127

	je .SPC

	; write the char to the output buffer

	mov [edi],al

	inc esi

	inc edi

	inc cx

	cmp cx,1024

	jge .DONE

	; print a CRLF after every 32 chars

	inc byte [count_1]

	cmp byte [count_1],32

	jl .PRINT

	mov byte [count_1],0

	add edx,32

	PRINT_CRLF

	; print an extra CRLF after every 8 rows (1 page of memory = 256 bytes)

	inc byte [count_2]

	cmp byte [count_2],8

	jl .NEXT

	mov byte [count_2],0

	PRINT_CRLF

  .NEXT:

	jmp .ROW

  .DONE:

	mov [edi],byte 0

	ret

endp

; -------------------------------------------------------------------------------------

section '.idata' import data readable writeable

  library kernel,'KERNEL32.DLL',\
	  user,'USER32.DLL'

  import kernel,\
	 GetModuleHandle,'GetModuleHandleA',\
	 ExitProcess,'ExitProcess'

  import user,\
	 DialogBoxParam,'DialogBoxParamA',\
	 GetDlgItem,'GetDlgItem',\
	 SetDlgItemText,'SetDlgItemTextA',\
	 GetDlgItemText,'GetDlgItemTextA',\
	 SendMessage,'SendMessageA',\
	 EndDialog,'EndDialog'

; -------------------------------------------------------------------------------------

section '.data' readable writeable

  bfCurrentLine rb 128

  bfLabel rb 16

  bfMnemonic rb 4

  bfOperand rb 112

  bfExpression rb 32

  bfSymbol rb 16

  Operand_Data rb 4

  Exe_Info rb 2

  Exe_Info_2345 rb 4

  Exe_Info_67 rb 2

  Exe_Info_89 rb 4

  pSymbol_Table dd 0

  Watch_Arr rb 48

  W_Arr_Index db 0

  Watch_On db 0

  Accumulator db 0

  Index_Reg_X db 0

  Index_Reg_Y db 0

  Stack_Pointer db 0

  NV_ZC db 0

  Next_Dlg_ID db 0

  Program_Counter dw 0x200

  Location_Counter dw 0x200

  Debug_Code dw 0

  Asm_Bytes dd 0

  Main_Memory rb 65536

  szInputText db "Enter code here and press [Compile Assembly]:",0

  cbString rb 32

  hCBX dd 0

  szErrMessage_0 db "Error: unknown compile error.",0
  szErrMessage_1 db "Error: length of input line must be less than 128 chars.",0
  szErrMessage_2 db "Error: extra chars in the line.",0
  szErrMessage_3 db "Error: length of label must be 14 chars or less.",0
  szErrMessage_4 db "Error: invalid chars in the mnemonic field.",0
  szErrMessage_5 db "Error: length of operand field must be less than 112 chars.",0
  szErrMessage_6 db "Error: too many chars in the mnemonic field.",0
  szErrMessage_7 db "Error: EQU, EPZ or DFS ops require a label.",0
  szErrMessage_8 db "Error: operand for EPZ must evaluate to a 1 byte value.",0
  szErrMessage_9 db "Error: label matches an existing entry in the symbol table.",0
  szErrMessage_10 db "Error: char after plus or minus sign is invalid.",0
  szErrMessage_11 db "Error: symbol table is full.",0
  szErrMessage_12 db "Error: invalid char in the operand.",0
  szErrMessage_13 db "Error: hex number contains an invalid char.",0
  szErrMessage_14 db "Error: decimal number contains an invalid char.",0
  szErrMessage_15 db "Error: binary number contains an invalid char.",0
  szErrMessage_16 db "Error: label contains invalid chars.",0
  szErrMessage_17 db "Error: unknown mnemonic.",0
  szErrMessage_18 db "Error: invalid mnemonic and operand size combination.",0
  szErrMessage_19 db "Error: decimal number in operand must be less than 65536.",0
  szErrMessage_20 db "Error: invalid chars in hex number.",0
  szErrMessage_21 db "Error: too many digits in number.",0
  szErrMessage_22 db "Error: invalid chars in binary number.",0
  szErrMessage_23 db "Error: invalid chars in decimal number.",0
  szErrMessage_24 db "Error: invalid chars in hex number.",0
  szErrMessage_25 db "Error: HEX op - max length of operand is 8 hex digits.",0
  szErrMessage_26 db "Error: invalid chars in hex number.",0
  szErrMessage_27 db "Error: max length of hex number is 4 digits.",0
  szErrMessage_28 db "Error: invalid chars in decimal number.",0
  szErrMessage_29 db "Error: max length of decimal number is 5 digits.",0
  szErrMessage_30 db "Error: decimal number in operand must be less than 65536.",0
  szErrMessage_31 db "Error: could not detect addressing mode of the operand.",0
  szErrMessage_32 db "Error: operand contains invalid chars.",0
  szErrMessage_33 db "Error: could not determine value of symbol in the operand.",0
  szErrMessage_34 db "Error: could not find symbol in the symbol table.",0
  szErrMessage_35 db "Error: cannot assemble the line - unknown mnemonic.",0
  szErrMessage_36 db "Error: cannot assemble the line - bad branch destination.",0
  szErrMessage_37 db "Error: cannot assemble the line - invalid addressing mode.",0
  szErrMessage_38 db "Failed execution error - unknown instruction:",0
  szErrMessage_39 db "Error: invalid chars in binary number.",0
  szErrMessage_40 db "Error: too many digits in binary number.",0
  szErrMessage_41 db "Error: the pseudo op must have an operand.",0
  szErrMessage_42 db "Error: bad input - enter a valid symbol or hex address.",0
  szErrMessage_43 db "Error: output buffer overflow - cannot finish compile.",0

  bfDisplay rb 32768

  bfAsmCode rb 32768

  bfOutput rb 32768

  pOutput dd 0

; -------------------------------------------------------------------------------------

section '.rc' resource data readable

  directory RT_DIALOG,dialogs

  resource dialogs,\
	   IDD_EDIT_DIALOG,LANG_ENGLISH+SUBLANG_DEFAULT,the_edit_dialog,\
	   IDD_RUN_DIALOG,LANG_ENGLISH+SUBLANG_DEFAULT,the_run_dialog,\
	   IDD_WATCH_DIALOG,LANG_ENGLISH+SUBLANG_DEFAULT,the_watch_dialog

  dialog the_edit_dialog,\
  '6502 Assembly Language Simulator',20,50,522,396,\
  DS_MODALFRAME+WS_MINIMIZEBOX+WS_POPUP+WS_VISIBLE+WS_CAPTION+WS_SYSMENU,\
  0,0,"Lucida Console",11

  dialogitem 'EDIT',0,IDC_INPUT,0,0,260,366,ES_MULTILINE+ES_AUTOVSCROLL+ES_WANTRETURN+WS_VSCROLL+WS_BORDER+WS_VISIBLE,0
  dialogitem 'EDIT',0,IDC_OUTPUT,261,0,260,366,ES_MULTILINE+ES_AUTOVSCROLL+ES_WANTRETURN+WS_VSCROLL+WS_BORDER+WS_VISIBLE,0

  dialogitem 'BUTTON',"Compile Assembly",IDC_BTN_COMPILE,7,375,80,14,BS_PUSHBUTTON+WS_VISIBLE,0
  dialogitem 'BUTTON',"View Output",IDC_BTN_VIEW_ASM,89,375,80,14,BS_PUSHBUTTON+WS_VISIBLE,0
  dialogitem 'BUTTON',"View Symbols",IDC_BTN_VIEW_SYM,171,375,80,14,BS_PUSHBUTTON+WS_VISIBLE,0
  dialogitem 'BUTTON',"Clear Assembly",IDC_BTN_CLR_ASM,253,375,80,14,BS_PUSHBUTTON+WS_VISIBLE,0
  dialogitem 'BUTTON',"Execute Code",IDC_BTN_NEXT_DLG,335,375,80,14,BS_PUSHBUTTON+WS_VISIBLE,0

  enddialog

  dialog the_run_dialog,\
  '6502 Assembly Language Simulator',20,50,522,396,\
  DS_MODALFRAME+WS_MINIMIZEBOX+WS_POPUP+WS_VISIBLE+WS_CAPTION+WS_SYSMENU,\
  0,0,"Lucida Console",11

  dialogitem 'EDIT',0,IDC_OUTPUT,0,0,260,206,ES_MULTILINE+ES_AUTOVSCROLL+ES_WANTRETURN+WS_VSCROLL+WS_BORDER+WS_VISIBLE,0
  dialogitem 'EDIT',0,IDC_DEBUG,0,207,260,78,ES_MULTILINE+ES_AUTOVSCROLL+ES_WANTRETURN+WS_VSCROLL+WS_BORDER+WS_VISIBLE,0
  dialogitem 'EDIT',0,IDC_STATUS,0,286,260,78,ES_MULTILINE+ES_AUTOVSCROLL+ES_WANTRETURN+WS_VSCROLL+WS_BORDER+WS_VISIBLE,0

  dialogitem 'EDIT',0,IDC_PAGES,262,0,260,280,ES_MULTILINE+ES_AUTOVSCROLL+ES_WANTRETURN+WS_VSCROLL+WS_BORDER+WS_VISIBLE,0

  dialogitem 'EDIT',0,IDC_ASCII_IO,262,303,260,60,ES_MULTILINE+ES_AUTOVSCROLL+ES_WANTRETURN+WS_VSCROLL+WS_BORDER+WS_VISIBLE,0

  dialogitem 'BUTTON',"Run Code",IDC_BTN_RUN,7,375,80,14,BS_PUSHBUTTON+WS_VISIBLE,0
  dialogitem 'BUTTON',"Step",IDC_BTN_STEP,89,375,80,14,BS_PUSHBUTTON+WS_VISIBLE,0
  dialogitem 'BUTTON',"Reset PC",IDC_BTN_RESET_PC,171,375,80,14,BS_PUSHBUTTON+WS_VISIBLE,0
  dialogitem 'BUTTON',"Reset Machine",IDC_BTN_RESET,253,375,80,14,BS_PUSHBUTTON+WS_VISIBLE,0
  dialogitem 'BUTTON',"View Watch",IDC_BTN_VIEW_WATCH,335,375,80,14,BS_PUSHBUTTON+WS_VISIBLE,0
  dialogitem 'BUTTON',"Edit Code",IDC_BTN_PREV_DLG,417,375,80,14,BS_PUSHBUTTON+WS_VISIBLE,0

  dialogitem 'COMBOBOX',"",IDC_CBX_PAGE_SELECT,262,286,80,80,CBS_DROPDOWNLIST+WS_VSCROLL+WS_VISIBLE

  dialogitem 'BUTTON',"Load ASCII",IDC_BTN_LOAD_ASC,344,286,80,12,BS_PUSHBUTTON+WS_VISIBLE,0
  dialogitem 'BUTTON',"Add To Watch",IDC_BTN_ADD_WATCH,426,286,80,12,BS_PUSHBUTTON+WS_VISIBLE,0

  enddialog

  dialog the_watch_dialog,\
  'Add To The Watch',50,80,200,100,\
  DS_MODALFRAME+WS_POPUP+WS_VISIBLE+WS_CAPTION+WS_SYSMENU,\
  0,0,"Lucida Console",11

  dialogitem "BUTTON","",IDC_GRP_BOX,3,2,194,92,BS_GROUPBOX+WS_VISIBLE,0

  dialogitem "STATIC","Enter a symbol name or hex address:",IDC_PROMPT_1,10,12,180,20,SS_LEFT+WS_GROUP+WS_VISIBLE,0
  dialogitem "STATIC","Enter the number of bytes to include:",IDC_PROMPT_2,10,42,180,20,SS_LEFT+WS_GROUP+WS_VISIBLE,0

  dialogitem 'EDIT',0,IDC_WATCH_ITEM,10,24,180,12,WS_BORDER+WS_VISIBLE,0
  dialogitem 'EDIT',0,IDC_WATCH_NBYTES,10,54,180,12,WS_BORDER+WS_VISIBLE,0

  dialogitem 'BUTTON',"Add",IDC_BTN_ADD,10,73,40,14,BS_PUSHBUTTON+WS_VISIBLE,0
  dialogitem 'BUTTON',"Close",IDC_BTN_CLOSE,52,73,40,14,BS_PUSHBUTTON+WS_VISIBLE,0

  enddialog

; -------------------------------------------------------------------------------------
Advertisements

Blog at WordPress.com.

%d bloggers like this: