Skip to content

feat: Add bit field comparison syntax to expression/condition language #204

Description

@CTalkobt

Feature Request: Bit Field Syntax (Read and Write)

Add support for bit field comparison and assignment operations in conditions and expressions using colon notation. Applies to both assembly (ca45 assertions) and C (cc45 compiler).

Syntax

var:5           # Read bit 5 (bits numbered 0..7)
var:5-7         # Read bits 5-7 (extract range)
var:5 = 1       # Compare bit 5 to value 1 (read)
var:5-7 = 3     # Compare bits 5-7 to value 3 (read)
var:5 = 0       # Set bit 5 to 0 (write)
var:5-7 = 2     # Set bits 5-7 to value 2 (write)

Use Cases

Assembly/Assertions (ca45)

Single Bit Checks (common in CPU flag testing):

; Check if carry flag is set
assert SR:0 = 1

; Check if zero flag is clear
assert SR:1 = 0

; Check if negative flag is set
assert SR:7 = 1

Bit Range Checks (for multi-bit fields):

; Check address mode bits (6-7)
assert opcode:6-7 = 2

; Check if any interrupt bits set (0-2)
assert INTERRUPT:0-2 = 0

C Language (cc45)

Read Operations (tests/conditionals):

// Test CPU flag
if (SR:7 = 1) {
    // Negative flag is set
}

// Hardware register check
while ((VIC_CONTROL:5) = 1) {
    // Wait for specific VIC-IV feature
}

// Interrupt handling
if (CIA_ICR:0-2 != 0) {
    handle_interrupt();
}

Write Operations (bit manipulation):

// Set bit 5 in flags register
flags:5 = 1;

// Clear bit 5 in flags register
flags:5 = 0;

// Set bits 5-7 to value 3
status:5-7 = 3;

// Common pattern: enable/disable features
VIC_CONTROL:5 = 1;  // Enable feature
VIC_CONTROL:5 = 0;  // Disable feature

// Hardware register configuration
SR:7 = 0;           // Clear negative flag
CIA_ICR:0-2 = 0;    // Clear interrupt bits 0-2

Implementation

Syntax Parser Enhancement

Modify expression/condition parser to recognize bit field syntax:

  • identifier:bit → single bit access
  • identifier:low-high → bit range access
  • Distinguish read context (comparison, conditional) from write context (assignment)

Code Generation Strategies

Read: Single Bit (most optimizable):

; var:5 = 1  →  (var >> 5) & 1 == 1
; Optimized:  → LDA var / BIT var / BVC/BVS

Read: Bit Range:

; var:5-7 = 3  →  (var >> 5) & 0x07 == 3
; Generated:    → LDA var / AND #0x07 / CMP #3

Write: Single Bit Clear:

; var:5 = 0  →  var &= ~(1 << 5)
; Generated:    → LDA var / AND #~0x20 / STA var

Write: Single Bit Set:

; var:5 = 1  →  var |= (1 << 5)
; Generated:    → LDA var / ORA #0x20 / STA var

Write: Bit Range:

; var:5-7 = 3  →  var = (var & ~0xE0) | (3 << 5)
; Generated:    → LDA var / AND #0x1F / ORA #0x60 / STA var

Generation Options

  1. Generic: AND mask + ORA value (for writes)

    • Works for all cases
    • Two extra instructions (AND, ORA) or one (CMP) for reads
  2. Single-bit optimized: BIT instruction (for reads)

    • Only for checking single bits
    • Uses built-in bit test (BIT opcode)
    • May be more efficient depending on context
  3. Shift + Compare (for reads):

    • For bits 0-2: no shift needed, just AND
    • For bits 3-7: shift right then AND and compare

Language Integration

Assembly (ca45):

  • Assert statements: assert SR:7 = 1
  • Comparisons in conditionals (not yet supported, but infrastructure can support)

C (cc45):

  • If conditions: if (var:5 = 1) { ... }
  • While loops: while (status:0-2 != 0) { ... }
  • Assignment statements: var:5 = 0;
  • Assignment with non-constant: flags:bits = some_value;
  • Compound assignments could be added later: var:5 += 1;

Symbol Support

Should work with:

  • Register names: SR:7 (negative flag)
  • Memory locations: $D020:4 (IRQ flag in VIC-II)
  • Variables: myvar:2-4
  • Struct fields: state.flags:5-7
  • Local variables: flags:5

Test Cases

Assembly Tests (ca45)

; Single bit read
assert SR:7 = 1

; Bit range read
assert opcode:6-7 = 2

; Memory address read
assert $D01E:0-2 = 0

C Tests (cc45)

// Single bit read/test
void test_bit_field_single_bit_read() {
    uint8_t val = 0x80;  // binary 10000000
    if (val:7 = 1) {
        // Success
    }
}

// Bit range read/test
void test_bit_field_range_read() {
    uint8_t val = 0xE0;  // binary 11100000
    if (val:5-7 = 7) {
        // Success
    }
}

// Single bit write
void test_bit_field_single_bit_write() {
    uint8_t val = 0x00;
    val:5 = 1;  // Set bit 5
    assert (val == 0x20);
    val:5 = 0;  // Clear bit 5
    assert (val == 0x00);
}

// Bit range write
void test_bit_field_range_write() {
    uint8_t val = 0x00;
    val:5-7 = 3;  // Set bits 5-7 to 3 (0x60)
    assert (val == 0x60);
    val:5-7 = 0;  // Clear bits 5-7
    assert (val == 0x00);
}

// Hardware register write (common pattern)
void configure_vic() {
    VIC_CONTROL:5 = 1;  // Enable feature
}

// CPU flag manipulation
void test_cpu_flags() {
    if (SR:7 = 1) {  // Check negative flag
        SR:7 = 0;    // Clear negative flag
    }
}

Code Generation Example

For SR:7 = 1 (test negative flag):

Current:

LDA SR
LSR A
LSR A
LSR A
LSR A
LSR A
LSR A
LSR A
CMP #1

With bit field syntax (optimized):

LDA SR
BIT SR    ; Sets N flag if bit 7 is set
BMI ...   ; Branch if minus (N flag set)

For flags:5 = 1 (set bit 5):

Current:

LDA flags
ORA #$20  ; Set bit 5
STA flags

With bit field syntax:

LDA flags
ORA #$20
STA flags

Priority

High — Very common use case for:

  • CPU state testing and assertions in compiler test suites (assembly)
  • Hardware register manipulation in systems code (C)
  • MEGA65 development where bit manipulation is idiomatic
  • Interrupt handling and flag management

Acceptance Criteria

Parser & Semantic Analysis:

  • Bit field syntax parsing (single bit and ranges)
  • Distinguish read context (comparison) from write context (assignment)
  • Evaluation with correct bit extraction/manipulation
  • Memory address support ($XXXX:y notation)
  • Symbol support (register names, variables, struct fields)
  • Type validation (lvalue for writes, rvalue for reads)

Code Generation:

  • Read: Optimized code for single-bit checks
  • Read: Correct bit extraction and comparison for ranges
  • Write: Correct bit masking and setting for single bits
  • Write: Correct read-modify-write for bit ranges
  • Peephole optimization for common patterns

Testing:

  • Comprehensive test coverage (12+ tests per language)
  • Read operations in conditionals
  • Write operations in statements
  • Bit range operations (both read and write)
  • Memory address references
  • Struct field bit access

Documentation:

  • Language specification update
  • Examples in cc45/ca45 docs
  • Assembly assertion syntax documented

Language Support:

  • Assembly (ca45) read operations in assert statements
  • C (cc45) read operations in conditionals and expressions
  • C (cc45) write operations in assignment statements
  • All existing tests still pass

Notes

  • This feature is particularly valuable for MEGA65 development where systems-level bit manipulation is common
  • Implementation for reads should happen first (lower complexity), writes second
  • Future enhancement: compound assignments (var:5 += 1;) can be added after basic write support
  • Consider adding intrinsic functions for advanced bit operations as future work

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions