I am unable to identify the root cause of the error in order to fix it and so I'm looking for help with how to track down and fix the problem. I'm using VisualStudio 2022 Community as my IDE. The same line of code is also causing two other errors, i.e., error A2006: undefined symbol : 1 and error A2077: instruction does not allow NEAR indirect addressing. The specific line of code identified by the assembler as erroneous is CheckItemForDuplicates TD17,TD27,TD37,TD47,TD57,TD67,TD77,TD87,TD97. This line of code is just one of nine similar lines of code in the procedure. The procedure includes the following code:
CheckColumnsForDuplicates proc
invoke CopyCurrentState ; For possible UNDO
RecordActionSteps ActionCode2 ;, CkColDUP
inc StepCounter
;---------------------------------------------------------------------------------
CheckItemForDuplicates TD11,TD21,TD31,TD41,TD51,TD61,TD71,TD81,TD91
CheckItemForDuplicates TD12,TD22,TD32,TD42,TD52,TD62,TD72,TD82,TD92
CheckItemForDuplicates TD13,TD23,TD33,TD43,TD53,TD63,TD73,TD83,TD93
CheckItemForDuplicates TD14,TD24,TD34,TD44,TD54,TD64,TD74,TD84,TD94
CheckItemForDuplicates TD15,TD25,TD35,TD45,TD55,TD65,TD75,TD85,TD95
CheckItemForDuplicates TD16,TD26,TD36,TD46,TD56,TD66,TD76,TD86,TD96
CheckItemForDuplicates TD17,TD27,TD37,TD47,TD57,TD67,TD77,TD87,TD97
CheckItemForDuplicates TD18,TD28,TD38,TD48,TD58,TD68,TD78,TD88,TD98
CheckItemForDuplicates TD19,TD29,TD39,TD49,TD59,TD69,TD79,TD89,TD99
;---------------------------------------------------------------------------------
RET
CheckColumnsForDuplicates endp
There are two other similar procedures named "CheckRowsForDuplicates" and "CheckBoxesForDuplicates" both of which execute the "CheckItemForDuplicates" MACRO nine times, each time with a different set of nine parameters. Consequently, it is not clear to me why this single line of code is identified as the cause of these errors and the other 26 similar lines of code are not also identified as the source of the same errors.
I've looked at the MACRO that is called by these three procedures to find any jumps or similar branching logic that might be the cause of the errors. As background, the MACRO is a part of a larger program I have been working on as a means to learn and apply assembly language with Win32 API commands. The program is intended to assist in solving Sudoku puzzles. The MACRO contains two "FOR" loops. The first "FOR" loop creates a bit MASK of Sudoku #s found in the 9 Sudoku cells that make up a row,column, or box in the Sudoku matrix and the 2nd "FOR" loop applies the inverse of the MASK to the remaining (unsolved) cells to identify DUPLICATES of the Sudoku #s found in the first "FOR" loop. In the first "FOR" loop, there is one "TEST" instruction with a corresponding "jz" instruction that includes s label "NextCell", which is LOCAL to the "FOR" loop. In the 2nd "FOR" loop there is logic to apply the MASK which I originally setup to use offsets to copy data, but changed to direct copies (i.e., mov) in an effort to elminate the errors but the same errors still continued to occur. I also searched the code for a "1" that somehow was being interpreted as an "undefined" symbol but found nothing that looked suspicious. I tried disabling sections of code by "commenting them out" but I was unable to narrow down the source of the error to any specific code. The MACRO I reviewed is:
CheckItemForDuplicates MACRO Cell1,Cell2,Cell3,Cell4,Cell5,Cell6,Cell7,Cell8,Cell9
; ***************************************************************************************************************************************************************************
; NOTES: An ITEM is either a Sudoku BOX, COLUMN or ROW..
; ***************************************************************************************************************************************************************************
mov MASKITEM,0
;******************************************************************************************
FOR CellX, <Cell1,Cell2,Cell3,Cell4,Cell5,Cell6,Cell7,Cell8,Cell9>
Local CellX, NextCell
;******************************************************************************************
;This loop CREATES a MASK of Given, Solved and/or Guessed Sudoku #s found in the 9 MatrixCells of the item under review (i.e., row, column, or box)
pushad ; Preparation steps: Save register values
mov ax, CellX ; Copy CellX (e.g.,TD11) to working memory
mov bx,ax ; keep spare copy of CellX in register bx to test Input/Solved Flags
TEST bx,MASK InputDataFlag + MASK SolvedFlag ; Check to determine if data is Input or Solved
jz NextCell ; If not Input or Solved Data, restore registers & process next matrix cell
; Otherwise, data is Input/Solved Data. So, get value.
AND ax, MASK DATABITS ; ... isolate value in the SPARE COPY of CellX previously copied into
; register ax in preparation steps
; -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
FOR N, <1,2,3,4,5,6,7,8,9>
LOCAL N
.IF ax==N
OR MASKITEM,MASK #CatStr(<Possibility>,<N>) ; Incorporate MASKs for all 9 cells of Item under review
.ENDIF
ENDM ; End of For N loop
; -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
NextCell:
popad
;******************************************************************************************
; If CellX value equals N, set MASK for ITEM to N
; Set Cell-1 MASK for ITEM-1 as described above. This MASK will incorporate
; ... ALL DUPLICATE POSSIBLITIES IDENTIFIED for the ITEM under review (i.e., Row,Col,Box)
;******************************************************************************************
ENDM ; End of For CellX CREATE MASK loop
;******************************************************************************************
; APPLY MASK
;******************************************************************************************
FOR CellX, <Cell1,Cell2,Cell3,Cell4,Cell5,Cell6,Cell7,Cell8,Cell9>
LOCAL CellX
; The combined MASK for the ITEM is applied to each of the 9 cells that the ITEM includes.
pushad
mov ax,CellX
mov bx, MASKITEM
NOT bx
AND ax,bx
mov CellX,ax
; mov ebx, offset CellX
; mov eax,[ebx]
; mov edx,offset MASKITEM
; mov ecx,[edx]
; NOT ecx
; AND eax,ecx
; mov CellX,ax ; ******* NOTE: CellX is NOT SOLVED until processed by ConfirmSudokuNumberFound MACRO *********
popad
ENDM ;End of For CellX Apply Mask loop
ENDM ;End of CheckItemForDuplicates macro
In my limited experience debugging assembly errors, I usually find a misspelling, an extra random character, or a missing character (e.g., a period, comma, semicolon, etc.) but this one has me baffled. I could use an expert's help in determining next steps in how to go about identifying and fixing the root cause of what to me is a mysterious error.
The code must output 'ccb',but output only 'c', LOOP is done only one time, i have calibrated in TD, but why LOOP is done only one time?
I THINK THAT I MUST TO DECREMENT STRING_LENGTH, SO I WROTE
DEC STRING_LENGTH
BUT IT NOT WORK, SO I WROTE LIKE THAT
MOV SP,STRING_LENGTH
DEC SP
MOV STRING_LENGTH,SP
I KNOW WHAT ARE YOU THINKING RIGHT NOW, THAT IS SO INCORRECT, YOU ARE RIGHT)))
I CAN USE C++, BUT I WANT TO DO IT ONLY IN ASSEMBLY,
DOSSEG
.MODEL SMALL
.STACK 200H
.DATA
STRING DB 'cScbd$'
STRING_LENGTH EQU $-STRING
STRING1 DB STRING_LENGTH DUP (?) , '$'
.CODE
MOV AX,#DATA
MOV DS,AX
XOR SI,SI
XOR DI,DI
MOV CX,STRING_LENGTH
S:
MOV BL,STRING[DI]
AND STRING[DI],01111100B
CMP STRING[DI],01100000B
JNE L1
MOV AL,BL
MOV STRING1[SI],AL
ADD SI,2
L1:
ADD DI,2
LOOP S
MOV DL,STRING1
MOV AH,9
INT 21H
MOV AH,4CH
INT 21H
END
In Turbo Debugger (TD.EXE) the F8 "F8 step" will execute the loop completely, until the cx becomes zero (you can even create infinite loop by updating cx back to some value, preventing it from reaching the 1 -> 0 step).
To get "single-step" out of the loop instruction, use the F7 "F7 trace" - that will cause the cx to go from 6 to 5, and the code pointer will follow the jump back on the start of the loop.
About some other issues of your code:
MOV SP,STRING_LENGTH
DEC SP
MOV STRING_LENGTH,SP
sp is not general purpose register, don't use it for calculation like this. Whenever some instruction does use stack implicitly (push, pop, call, ret, ...), the values are being written and read in memory area addressed by the ss:sp register pair, so by manipulating the sp value you are modifying the current "stack".
Also in 16 bit x86 real mode all the interrupts (keyboard, timer, ...), when they occur, the current state of flag register and code address is stored into stack, before giving the control to the interrupt handler code, which usually will push additional values to the stack, so whatever is in memory on addresses below current ss:sp is not safe in 16 bit x86 real mode, and the memory content keeps "randomly" changing there by all the interrupts being executed meanwhile (the TD.EXE itself does use part of this stack memory after every single step).
For arithmetic use other registers, not sp. Once you will know enough about "stack", you will understand what kind of sp manipulation is common and why (like sub sp,40 at beginning of function which needs additional "local" memory space), and how to restore stack back into expected state.
One more thing about that:
MOV SP,STRING_LENGTH
DEC SP
MOV STRING_LENGTH,SP
The STRING_LENGTH is defined by EQU, which makes it compile time constant, and only compile time. It's not "variable" (memory allocation), contrary to the things like someLabel dw 1345, which cause the assembler to emit two bytes with values 0100_0001B, 0000_0101B (when read as 16 bit word in little-endian way, that's value 1345 encoded), and the first byte address has symbolic name someLabel, which can be used in further instructions, like dec word ptr [someLabel] to decrement that value in memory from 1345 to 1344 during runtime.
But EQU is different, it assigns the symbol STRING_LENGTH final value, like 14.
So your code can be read as:
mov sp,14 ; makes almost sense, (practically destroys stack setup)
dec sp ; still valid
mov 14,sp ; doesn't make any sense, constant can't be destination for MOV
The first time my PIC30F code reads a word from Data EEPROM, it reads 0xFFFF instead of the data actually in EEPROM. It reads fine afterward.
After a bad read, I checked W1 and it does have the correct address
There are no words in data EEPROM with a value of 0xFFFF
I checked the supply: it's 5.13 V
If I break right before the table read instruction, and step through it, it woks fine
I know that NVMADRU and NVMADR are not involved in reading, but I checked them, and their value doesn't change between good reads and bad reads
It's a dsPIC30F5011
I checked the Errata, and did not find any reference to such issue
I am working through the debug function of MPLAB 8, with a PICkit II
I am working through the debug function of MPLAB 8, with a PICkit II: I reset, then run, and it fails
If I place the code in a tight loop until the value is correct, and counting the number of iterations, I see that it takes 2339 times through the loop until it reads correctly
EEPROM read code:
_ReadEEWord:
;--------------------------------------------------------------------------------
; Read a word from Data EEPROM
; Entry W0 Word address relative to the start of Data EEPROM
; Exit W0 Word at that location
; Uses W1, Table pointer
;--------------------------------------------------------------------------------
; Start address of Data EEPROM
#define DATAEE_START 0x7FFC00
; Setup pointer to EEPROM memory
mov #0x7F,W1 ; Set the table pointer
mov W1,TBLPAG ; to the page with the EEPROM
add W0,W0,W0 ; Convert the word address to a byte address
mov #0xFC00,W1 ; Add the start of EEPROM
add W1,W0,W1 ; to the address
nop
nop
nop
; Return the EEPROM data
tblrdl [W1],W0 ; Read the EEPROM data
nop
nop
nop
return
Any suggestions of what may be causing that?
SOLVED
The documentation doesn't say so, but, before you can read data EEPROM, you must wait for any previous EEPROM operations to be done.
You can do it in one of these ways:
1) In C:
#include <libpic30.h> // Includes EEPROM utilities
_wait_eedata(); // Wait for the erase to be done
2) In C, no lib import
while (NVMCONbits.WR);
3) In assembly:
btsc NVMCON,#15 ; If busy (WR bit s set)
bra $-2 ; Go back and wait
I have a PE file and I try to disassemble it in order to get it's instructions. However I noticed that .text segment contains not only instructions but also some data (I used IDA to notice that). Here's the example:
.text:004037E4 jmp ds:__CxxFrameHandler3
.text:004037EA ; [00000006 BYTES: COLLAPSED FUNCTION _CxxThrowException. PRESS KEYPAD "+" TO EXPAND]
.text:004037F0 ;
.text:004037F0 mov ecx, [ebp-10h]
.text:004037F3 jmp ds:??1exception#std##UAE#XZ ; std::exception::~exception(void)
.text:004037F3 ;
.text:004037F9 byte_4037F9 db 8Bh, 54h, 24h ; DATA XREF: sub_401440+2o
.text:004037FC dd 0F4428D08h, 33F04A8Bh, 0F6B2E8C8h, 0C4B8FFFFh, 0E9004047h
.text:004037FC dd 0FFFFFFD0h, 3 dup(0CCCCCCCCh), 0E904458Bh, 0FFFFD9B8h
.text:00403828 dword_403828 dd 824548Bh, 8BFC428Dh, 0C833F84Ah, 0FFF683E8h, 47F0B8FFh
.text:00403828 ; DATA XREF: sub_4010D0+2o
.text:00403828 ; .text:00401162o
.text:00403828 dd 0A1E90040h, 0CCFFFFFFh, 3 dup(0CCCCCCCCh), 50E0458Dh
.text:00403828 dd 0FFD907E8h, 458DC3FFh, 0D97EE9E0h
.text:00403860 db 2 dup(0FFh)
.text:00403862 word_403862 dw 548Bh
How can I distinct such data from instructions? My solution to this problem was to find simply the first instruction (enter address) and visit each instruction and all called functions. Unfortunatelly it occured that there are some blocks of code which are not directly called but their addresses are in .rdata segment among some data and I have no idea how distinct valid instruction addresses from data.
To sum up: is there any way to decide whether some address in .text segment contains data or instructions? Or maybe is there any way to decide which potential addresses in .rdata should be interpreted as instructions addresses and which as data?
You cannot, in general. The .text section of a PE file can mix up code and constants any way the author likes. Programs like IDA try to make sense of this by starting with the entrypoints and then disassembling, and seeing which addresses are targets of jumps, and which of reads. But devious programs can 'pun' between instructions and data.
Count the number of characters in an input line and terminate if enter is pressed.
MOV AX, 1
MOV AL, 0
INPUT: INT 21H
INC AL
CMP DL,'\n'
JE OUT
LOOP INPUT
OUT:
In the above code I have used \n. I am curious if we can use it or I would have to use the ascii code of it? Please help.
It depends entirely on your assembler. Probably yes, otherwise use an ascii table to translate it (to 0x0A or 10) yourself.
You should probably just try assembling it and see whether it works.
'\n' is not an assembly language constant. At least not in most assembly languages.
You will have to convert it directly using the character set in use. You can safely assume ASCII on almost all modern processors, so \n will be 10 (decimal) on most operating systems. On Windows the two-character sequence 13 and 10 is used.