- Notifications
You must be signed in to change notification settings - Fork27
More fixes towards v1.0#52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes fromall commits
1cb0db35e8ab92c9ff24dd90a0e8ff7db426fa631ab3ae44278e9812File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -342,9 +342,9 @@ def get_rel(arg): | ||
| if arg.type == IMM: | ||
| if arg.value & 3 != 0: # bitwise version of: arg.value % 4 != 0 | ||
| raise ValueError('Relative offset must be a multiple of 4') | ||
| returnIMM,arg.value >> 2 # bitwise version of: arg.value // 4 | ||
| if arg.type == SYM: | ||
| returnSYM,symbols.resolve_relative(arg.value) | ||
| raise TypeError('wanted: immediate, got: %s' % arg.raw) | ||
| @@ -449,7 +449,7 @@ def i_tsens(reg_dest, delay): | ||
| return _tsens.all | ||
| def i_adc(reg_dest, adc_idx, mux, _not_used=None): | ||
| _adc.dreg = get_reg(reg_dest) | ||
| _adc.mux = get_imm(mux) | ||
| _adc.sar_sel = get_imm(adc_idx) | ||
| @@ -619,7 +619,8 @@ def i_jump(target, condition='--'): | ||
| raise ValueError("invalid flags condition") | ||
| if target.type == IMM or target.type == SYM: | ||
| _bx.dreg = 0 | ||
| # we track label addresses in 32bit words, but immediate values are in bytes and need to get divided by 4. | ||
| _bx.addr = get_abs(target) if target.type == SYM else get_abs(target) >> 2 # bitwise version of "// 4" | ||
Collaborator There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. I don't get this. If it is a symbol, it directly uses its value (absolute address) else it uses an immediate offset // 4? Considering everything else in the opcode is the same, how does the cpu know what to do? like whether it is an offset or an absolute address? CollaboratorAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. In both cases what the machine instruction gets is an absolute address (not relative offset). The absolute address is either the address of a label, or an absolute address specified as immediate value. What is different in the two cases is that the assembler instruction must take an address given in bytes, while the machine instruction needs to contain the address in words. Because in py-esp32-ulp we already track label addresses in words internally, we do not need to divide those symbol addresses by 4. But for immediate values we need to (see:https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/ulp_instruction_set.html#note-about-addressing). Does that make sense, or did I miss what you asked? However... I did just discover one more case for the JUMP instruction, where we don't properly divide by 4. So this current logic is not 100% perfect. It appears to be that it's not only IMM values that must be divided by 4, but also symbol values that we internally label with the ABS type (as opposed to REL). Those ABS type symbols are defined by This logic is starting to look valid to me, the more I think about it. It should give the same result for the cases currently handled correctly, but also for the case of symbols defined with Collaborator There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. thanks for explaining, please add a comment above this like: Collaborator There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Maybe we could also have ABS1 (byte addresses), ABS4 (32bit word addrs), etc. so we better know what we have. CollaboratorAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. So, my last part about the REL vs ABS, I think is not relevant anymore. I believe that "one more case" I talked about above, is actually a bug in binutils-esp32ulp I have now tested quite a bit more and stepped through binutils-esp32ulp a bit and found the following: whether the value (that was defined with The reason I started to get skeptical is that binutils-esp32ulp behaves correctly for JUMPS and JUMPR cases, as per description in the documentation:https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/ulp_instruction_set.html#note-about-addressing. The documentation shows an example, where values, which come from I think the issues comes up in binutils-esp32ulp, depending on where the value is actually "filled-in" into the instruction. For non-global symbols, the value is already set during the assembly stage ( So that means, I would not change anything in our implementation (other than adding the comment you suggested). I might file a bug report to the binutils-esp32ulp project. Collaborator There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Yeah, sounds strange, please file a bug. CollaboratorAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. I filed a bug report now:espressif/binutils-esp32ulp#22 | ||
| _bx.unused = 0 | ||
| _bx.reg = 0 | ||
| _bx.type = jump_type | ||
| @@ -652,7 +653,7 @@ def _jump_relr(threshold, cond, offset): | ||
| def i_jumpr(offset, threshold, condition): | ||
| offset_type,offset = get_rel(offset) | ||
| threshold = get_imm(threshold) | ||
| condition = get_cond(condition) | ||
| if condition == 'lt': | ||
| @@ -669,7 +670,11 @@ def i_jumpr(offset, threshold, condition): | ||
| # jump over next JUMPR | ||
| skip_ins = _jump_relr(threshold + 1, BRCOND_GE, 2) | ||
| # jump to target | ||
| if (offset_type == IMM and offset < 0) or offset_type == SYM: | ||
| # adjust for the additional JUMPR instruction | ||
| # for IMM offsets, the offset is relative to the 2nd instruction, so only backwards jumps need adjusting | ||
| # for SYM offsets, label offsets already include the extra instruction, so both directions need adjusting | ||
| offset -= 1 | ||
| jump_ins = _jump_relr(threshold, BRCOND_GE, offset) | ||
| return (skip_ins, jump_ins) | ||
| else: | ||
| @@ -691,7 +696,7 @@ def _jump_rels(threshold, cond, offset): | ||
| def i_jumps(offset, threshold, condition): | ||
| offset_type,offset = get_rel(offset) | ||
| threshold = get_imm(threshold) | ||
| condition = get_cond(condition) | ||
| if condition == 'lt': | ||
| @@ -711,7 +716,11 @@ def i_jumps(offset, threshold, condition): | ||
| # jump over next JUMPS | ||
| skip_ins = _jump_rels(threshold, skip_cond, 2) | ||
| # jump to target | ||
| if (offset_type == IMM and offset < 0) or offset_type == SYM: | ||
| # adjust for the additional JUMPS instruction | ||
| # for IMM offsets, the offset is relative to the 2nd instruction, so only backwards jumps need adjusting | ||
| # for SYM offsets, label offsets already include the extra instruction, so both directions need adjusting | ||
| offset -= 1 | ||
| jump_ins = _jump_rels(threshold, jump_cond, offset) | ||
| return (skip_ins, jump_ins) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -53,6 +53,32 @@ def test_parse_line(): | ||
| assert a.parse_line(next(lines)) == (None, '.data', ()) # test left-aligned directive is not treated as label | ||
| def test_parse_labels_correctly(): | ||
| """ | ||
| description of what defines a label | ||
| https://sourceware.org/binutils/docs/as/Statements.html | ||
| https://sourceware.org/binutils/docs/as/Labels.html | ||
| """ | ||
| a = Assembler() | ||
| assert a.parse_line('') is None | ||
| assert a.parse_line('label: .set const, 42') == ('label', '.set', ('const', '42',)) | ||
| assert a.parse_line('label:.set const, 42') == ('label', '.set', ('const', '42',)) | ||
| assert a.parse_line('label:') == ('label', None, ()) | ||
| assert a.parse_line(' label:') == ('label', None, ()) | ||
| assert a.parse_line(' label: ') == ('label', None, ()) | ||
ThomasWaldmann marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| assert a.parse_line('nop ') == (None, 'nop', ()) | ||
| assert a.parse_line('.set c, 1 ') == (None, '.set', ('c', '1',)) | ||
| assert a.parse_line('invalid : nop') == (None, 'invalid', (': nop',)) # no whitespace between label and colon | ||
| assert a.parse_line('.string "hello world"') == (None, '.string', ('"hello world"',)) | ||
| assert a.parse_line('.string "hello : world"') == (None, '.string', ('"hello : world"',)) # colon in string | ||
| assert a.parse_line('label::') == ('label', ':', ()) | ||
| assert a.parse_line('label: :') == ('label', ':', ()) | ||
| assert a.parse_line('a_label:') == ('a_label', None, ()) | ||
| assert a.parse_line('$label:') == ('$label', None, ()) | ||
| assert a.parse_line('.label:') == ('.label', None, ()) | ||
| assert a.parse_line('&label:') == (None, '&label:', ()) # & not a valid char in a label | ||
| def test_parse(): | ||
| a = Assembler() | ||
| lines = remove_comments(src) | ||
| @@ -260,6 +286,7 @@ def test_support_multiple_statements_per_line(): | ||
| test_parse_line() | ||
| test_parse_labels_correctly() | ||
| test_parse() | ||
| test_assemble() | ||
| test_assemble_bss() | ||