Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions memory/MEMORY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# AVR8Sharp Project Memory

## Project Structure
- Solution: `AVR8Sharp.sln` at repo root
- Core lib: `src/AVR8Sharp.Core/` (multi-target: net6, net8, netstandard1.2, netstandard2.0, net10)
- TestKit: `src/Avr8Sharp.TestKit/` (net10, FluentAssertions 6.12.0)
- Tests: `tests/Avr8Sharp.Tests/` (NUnit, net10)
- Demo: `src/Avr8Sharp.Demo/` (net10)

## TestKit Architecture (created 2026-02-28)
See `memory/testkit.md` for details.

Key entry point:
```csharp
var sim = AvrTestSimulation.Create()
.WithFrequency(16_000_000)
.WithHex(hexString) // or .WithAsm() / .WithProgram()
.AddGpio(AvrIoPort.PortBConfig, out var portB)
.AddUsart(AvrUsart.Usart0Config, out var serial)
.AddTimer(AvrTimer.Timer0Config);

sim.RunMilliseconds(500);

portB.Should().HavePinHigh(5);
serial.Should().Contain("Hello");
sim.Cpu.Should().HaveRegister(24, 42);
sim.Memory.Should().HaveByteAt(0x200, 0xFF);
```

Pre-configured boards (src/Avr8Sharp.TestKit/Boards/):
- ArduinoUnoSimulation — ATmega328P, 16 MHz, PortB/C/D, Timer0/1/2, Serial
- ArduinoMegaSimulation — ATmega2560, 16 MHz, PortA-L, Timer0-4, Serial0/1/2
- ATtiny85Simulation — ATtiny85, 8 MHz, PortB, Timer0

CI/CD workflows (.github/workflows/):
- ci.yml — build + test on every push/PR (GitHub + Gitea compatible)
- publish.yml — pack + push NuGet on tag/main/dispatch; uses secrets:
NUGET_PRIVATE_SOURCE_URL, NUGET_PRIVATE_API_KEY, NUGET_PUBLIC_API_KEY
- build-nugets.yml — deprecated stub (replaced by publish.yml)

NuGet.Config: XML comments must NOT contain '--' (invalid XML).

## Key Namespaces
- `Avr8Sharp.TestKit` — AvrTestSimulation, AvrMemoryView, AssertionExtensions
- `Avr8Sharp.TestKit.Probes` — SerialProbe
- `Avr8Sharp.TestKit.Assertions` — AvrCpuAssertions, AvrGpioAssertions, SerialProbeAssertions, AvrMemoryAssertions

## Core CPU Facts
- `Cpu.Data[0..31]` = general registers R0–R31
- `Cpu.Data[93..94]` = SP (little-endian via DataView)
- `Cpu.Data[95]` = SREG
- `Cpu.PC` = word address (byte address = PC × 2)
- `Cpu.Cycles` = int (wraps ~134 s at 16 MHz)
- BREAK opcode = 0x9598

## Existing Test Utilities
`tests/Avr8Sharp.Tests/Utils.cs` has `TestProgramRunner` and `AsmProgram()` helpers
(these are superseded by TestKit for new tests).
71 changes: 71 additions & 0 deletions memory/testkit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Avr8Sharp.TestKit — Design Notes

## Files Created
```
src/Avr8Sharp.TestKit/
├── Avr8Sharp.TestKit.csproj # FluentAssertions 6.12.0 + Core ref
├── AvrTestSimulation.cs # Fluent builder + execution engine
├── AvrMemoryView.cs # Read-only SRAM wrapper for assertions
├── Probes/
│ └── SerialProbe.cs # Captures USART TX bytes
├── Assertions/
│ ├── AvrCpuAssertions.cs # HaveRegister, HavePC, HaveSP, SREG flags
│ ├── SerialProbeAssertions.cs # Contain, StartWith, ContainLine, etc.
│ ├── AvrGpioAssertions.cs # HavePinHigh, HavePinLow, HaveOutputValue
│ └── AvrMemoryAssertions.cs # HaveByteAt, HaveWordAt, HaveBytesAt
└── Extensions/
└── AssertionExtensions.cs # .Should() for AvrCpu, SerialProbe, AvrIoPort, AvrMemoryView
```

## AvrTestSimulation API

### Configuration (builder methods, all return `this`)
- `.Create(flashSize, sramBytes)` — static factory (default: 0x8000, 8192)
- `.WithFrequency(uint hz)` — default 16 MHz
- `.LoadHex(string)` — Intel HEX (gcc/avra output)
- `.LoadAsm(string)` — inline assembly via AvrAssembler
- `.LoadBytes(byte[])` — raw binary
- `.AddGpio(AvrPortConfig, out AvrIoPort)`
- `.AddUsart(AvrUsartConfig, out SerialProbe)` — auto-captures TX
- `.AddUsart(AvrUsartConfig)` — no capture
- `.AddTimer(AvrTimerConfig)` / `.AddTimer(config, out AvrTimer)`
- `.AddSpi(AvrSpiConfig, out AvrSpi)`
- `.AddTwi(AvrTwiConfig, out AvrTwi)`
- `.AddAdc(AvrAdcConfig, out AvrAdc)`

### Execution (all return `this`)
- `.RunCycles(long)` — precise cycle count
- `.RunMilliseconds(double)` — simulated time
- `.RunInstructions(int)` — instruction count
- `.RunUntil(Func<AvrTestSimulation,bool>, maxInstructions=100_000)`
- `.RunToBreak(maxInstructions=100_000)` — stops AT BREAK (0x9598), not executing it
- `.RunToAddress(int byteAddress, maxInstructions=100_000)`

## Assertion Classes

### AvrCpuAssertions (`cpu.Should()`)
- `.HaveRegister(index, byte)` — R0–R31
- `.HavePC(uint)` — word address
- `.HaveSP(ushort)`
- `.HaveCycles(int)`
- `.HaveSreg(byte)` — raw SREG byte
- `.HaveCarryFlag(bool=true)` / `.HaveZeroFlag` / `.HaveNegativeFlag` / `.HaveOverflowFlag` / `.HaveHalfCarryFlag` / `.HaveInterruptsEnabled`

### SerialProbeAssertions (`serial.Should()`)
- `.Contain(string)` / `.NotContain` / `.StartWith` / `.EndWith` / `.Be`
- `.BeEmpty()`
- `.HaveLineCount(int)` / `.ContainLine(string)`

### AvrGpioAssertions (`portB.Should()`)
- `.HavePinHigh(int)` / `.HavePinLow(int)` / `.HavePinInput(int)` / `.HavePinInputPullup(int)`
- `.HavePinState(int, PinState)`
- `.HaveOutputValue(byte)` — bitmask of all 8 output pins

### AvrMemoryAssertions (`sim.Memory.Should()`)
- `.HaveByteAt(address, byte)` / `.HaveWordAt(address, ushort)` / `.HaveWordBEAt` / `.HaveBytesAt(address, byte[])`

## SerialProbe
- `probe.Text` — all captured output as string
- `probe.Lines` — split on '\n', '\r' trimmed
- `probe.Clear()` — reset buffer
- `probe.InjectByte(byte)` — simulate incoming RX byte (calls `AvrUsart.WriteByte`)
Loading
Loading