diff options
| author | lironh | 2020-03-21 09:52:53 +0200 |
|---|---|---|
| committer | lironh | 2020-03-22 21:08:30 +0200 |
| commit | 8934a7566a038a74464d3d8df9d04fd875e5b1d7 (patch) | |
| tree | e131c263938081e6c89f39f141f3f20f6da8f851 /src/twi.spec.ts | |
| parent | Merge pull request #19 from gfeun/main-execute-loop-optimization (diff) | |
| download | avr8js-8934a7566a038a74464d3d8df9d04fd875e5b1d7.tar.gz avr8js-8934a7566a038a74464d3d8df9d04fd875e5b1d7.tar.bz2 avr8js-8934a7566a038a74464d3d8df9d04fd875e5b1d7.zip | |
refactor: added peripherals and cpu feature folders
Diffstat (limited to 'src/twi.spec.ts')
| -rw-r--r-- | src/twi.spec.ts | 390 |
1 files changed, 0 insertions, 390 deletions
diff --git a/src/twi.spec.ts b/src/twi.spec.ts deleted file mode 100644 index 369f22a..0000000 --- a/src/twi.spec.ts +++ /dev/null @@ -1,390 +0,0 @@ -import { CPU } from './cpu'; -import { AVRTWI, twiConfig } from './twi'; -import { assemble } from './utils/assembler'; -import { avrInstruction } from './instruction'; - -const FREQ_16MHZ = 16e6; - -function asmProgram(source: string) { - const { bytes, errors, lines } = assemble(source); - if (errors.length) { - throw new Error('Assembly failed: ' + errors); - } - return { program: new Uint16Array(bytes.buffer), lines }; -} - -function runInstructions(cpu: CPU, twi: AVRTWI, count: number) { - for (let i = 0; i < count; i++) { - if (cpu.progMem[cpu.pc] === 0x9598) { - console.log(cpu.data[0xbc].toString(16)); - console.log(cpu.data[16]); - throw new Error('BREAK instruction encountered'); - } - avrInstruction(cpu); - twi.tick(); - } -} - -describe('TWI', () => { - const TWINT = 7; - const TWSTA = 5; - const TWEN = 2; - - it('should correctly calculate the sclFrequency from TWBR', () => { - const cpu = new CPU(new Uint16Array(1024)); - const twi = new AVRTWI(cpu, twiConfig, FREQ_16MHZ); - cpu.writeData(0xb8, 0x48); // TWBR <- 0x48 - cpu.writeData(0xb9, 0); // TWSR <- 0 (prescaler: 1) - expect(twi.sclFrequency).toEqual(100000); - }); - - it('should take the prescaler into consideration when calculating sclFrequency', () => { - const cpu = new CPU(new Uint16Array(1024)); - const twi = new AVRTWI(cpu, twiConfig, FREQ_16MHZ); - cpu.writeData(0xb8, 0x03); // TWBR <- 0x03 - cpu.writeData(0xb9, 0x01); // TWSR <- 1 (prescaler: 4) - expect(twi.sclFrequency).toEqual(400000); - }); - - it('should trigger data an interrupt if TWINT is set', () => { - const cpu = new CPU(new Uint16Array(1024)); - const twi = new AVRTWI(cpu, twiConfig, FREQ_16MHZ); - cpu.writeData(0xbc, 0x81); // TWCR <- TWINT | TWIE - cpu.data[95] = 0x80; // SREG: I------- - twi.tick(); - expect(cpu.pc).toEqual(0x30); // 2-wire Serial Interface Vector - expect(cpu.cycles).toEqual(2); - expect(cpu.data[0xbc] & 0x80).toEqual(0); // UCSR0A should clear TWINT - }); - - describe('Master mode', () => { - it('should call the startEvent handler when TWSTA bit is written 1', () => { - const cpu = new CPU(new Uint16Array(1024)); - const twi = new AVRTWI(cpu, twiConfig, FREQ_16MHZ); - jest.spyOn(twi.eventHandler, 'start'); - cpu.writeData(0xbc, (1 << TWINT) | (1 << TWSTA) | (1 << TWEN)); - twi.tick(); - expect(twi.eventHandler.start).toHaveBeenCalledWith(false); - }); - - it('should successfully transmit a byte to a slave', () => { - // based on the example in page 225 of the datasheet: - // https://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061A.pdf - const { program } = asmProgram(` - ; register addresses - _REPLACE TWSR, 0xb9 - _REPLACE TWDR, 0xbb - _REPLACE TWCR, 0xbc - - ; TWCR bits - _REPLACE TWEN, 0x04 - _REPLACE TWSTO, 0x10 - _REPLACE TWSTA, 0x20 - _REPLACE TWINT, 0x80 - - ; TWSR states - _REPLACE START, 0x8 ; TWI start - _REPLACE MT_SLA_ACK, 0x18 ; Slave Adresss ACK has been received - _REPLACE MT_DATA_ACK, 0x28 ; Data ACK has been received - - ; Send start condition - ldi r16, TWEN - sbr r16, TWSTA - sbr r16, TWINT - sts TWCR, r16 - - ; Wait for TWINT Flag set. This indicates that the START condition has been transmitted - call wait_for_twint - - ; Check value of TWI Status Register. Mask prescaler bits. If status different from START go to ERROR - lds r16, TWSR - andi r16, 0xf8 - cpi r16, START - brne error - - ; Load SLA_W into TWDR Register. Clear TWINT bit in TWCR to start transmission of address - ; 0x44 = Address 0x22, write mode (R/W bit clear) - _REPLACE SLA_W, 0x44 - ldi r16, SLA_W - sts TWDR, r16 - ldi r16, TWINT - sbr r16, TWEN - sts TWCR, r16 - - ; Wait for TWINT Flag set. This indicates that the SLA+W has been transmitted, and ACK/NACK has been received. - call wait_for_twint - - ; Check value of TWI Status Register. Mask prescaler bits. If status different from MT_SLA_ACK go to ERROR - lds r16, TWSR - andi r16, 0xf8 - cpi r16, MT_SLA_ACK - brne error - - ; Load DATA into TWDR Register. Clear TWINT bit in TWCR to start transmission of data - _replace DATA, 0x55 - ldi r16, DATA - sts TWDR, r16 - ldi r16, TWINT - sbr r16, TWEN - sts TWCR, r16 - - ; Wait for TWINT Flag set. This indicates that the DATA has been transmitted, and ACK/NACK has been received - call wait_for_twint - - ; Check value of TWI Status Register. Mask prescaler bits. If status different from MT_DATA_ACK go to ERROR - lds r16, TWSR - andi r16, 0xf8 - cpi r16, MT_DATA_ACK - brne error - - ; Transmit STOP condition - ldi r16, TWINT - sbr r16, TWEN - sbr r16, TWSTO - sts TWCR, r16 - - ; Wait for TWINT Flag set. This indicates that the STOP condition has been sent - call wait_for_twint - - ; Check value of TWI Status Register. The masked value should be 0xf8 once done - lds r16, TWSR - andi r16, 0xf8 - cpi r16, 0xf8 - brne error - - ; Indicate success by loading 0x42 into r17 - ldi r17, 0x42 - - loop: - jmp loop - - ; Busy-waits for the TWINT flag to be set - wait_for_twint: - lds r16, TWCR - andi r16, TWINT - breq wait_for_twint - ret - - ; In case of an error, toggle a breakpoint - error: - break - `); - const cpu = new CPU(program); - const twi = new AVRTWI(cpu, twiConfig, FREQ_16MHZ); - twi.eventHandler = { - start: jest.fn(), - stop: jest.fn(), - connectToSlave: jest.fn(), - writeByte: jest.fn(), - readByte: jest.fn() - }; - - // Step 1: wait for start condition - runInstructions(cpu, twi, 4); - expect(twi.eventHandler.start).toHaveBeenCalledWith(false); - - runInstructions(cpu, twi, 16); - twi.completeStart(); - - // Step 2: wait for slave connect in write mode - runInstructions(cpu, twi, 16); - expect(twi.eventHandler.connectToSlave).toHaveBeenCalledWith(0x22, true); - - runInstructions(cpu, twi, 16); - twi.completeConnect(true); - - // Step 3: wait for first data byte - runInstructions(cpu, twi, 16); - expect(twi.eventHandler.writeByte).toHaveBeenCalledWith(0x55); - - runInstructions(cpu, twi, 16); - twi.completeWrite(true); - - // Step 4: wait for stop condition - runInstructions(cpu, twi, 16); - expect(twi.eventHandler.stop).toHaveBeenCalled(); - - runInstructions(cpu, twi, 16); - twi.completeStop(); - - // Step 5: wait for the assembly code to indicate success by settings r17 to 0x42 - runInstructions(cpu, twi, 16); - expect(cpu.data[17]).toEqual(0x42); - }); - - it('should successfully receive a byte from a slave', () => { - const { program } = asmProgram(` - ; register addresses - _REPLACE TWSR, 0xb9 - _REPLACE TWDR, 0xbb - _REPLACE TWCR, 0xbc - - ; TWCR bits - _REPLACE TWEN, 0x04 - _REPLACE TWSTO, 0x10 - _REPLACE TWSTA, 0x20 - _REPLACE TWEA, 0x40 - _REPLACE TWINT, 0x80 - - ; TWSR states - _REPLACE START, 0x8 ; TWI start - _REPLACE MT_SLAR_ACK, 0x40 ; Slave Adresss ACK has been received - _REPLACE MT_DATA_RECV, 0x50 ; Data has been received - _REPLACE MT_DATA_RECV_NACK, 0x58 ; Data has been received, NACK has been returned - - ; Send start condition - ldi r16, TWEN - sbr r16, TWSTA - sbr r16, TWINT - sts TWCR, r16 - - ; Wait for TWINT Flag set. This indicates that the START condition has been transmitted - call wait_for_twint - - ; Check value of TWI Status Register. Mask prescaler bits. If status different from START go to ERROR - lds r16, TWSR - andi r16, 0xf8 - ldi r18, START - cpse r16, r18 - jmp error ; only jump if r16 != r18 (START) - - ; Load SLA_R into TWDR Register. Clear TWINT bit in TWCR to start transmission of address - ; 0xa1 = Address 0x50, read mode (R/W bit set) - _REPLACE SLA_R, 0xa1 - ldi r16, SLA_R - sts TWDR, r16 - ldi r16, TWINT - sbr r16, TWEN - sts TWCR, r16 - - ; Wait for TWINT Flag set. This indicates that the SLA+W has been transmitted, and ACK/NACK has been received. - call wait_for_twint - - ; Check value of TWI Status Register. Mask prescaler bits. If status different from MT_SLA_ACK go to ERROR - lds r16, TWSR - andi r16, 0xf8 - cpi r16, MT_SLAR_ACK - brne error - - ; Clear TWINT bit in TWCR to receive the next byte, set TWEA to send ACK - ldi r16, TWINT - sbr r16, TWEA - sbr r16, TWEN - sts TWCR, r16 - - ; Wait for TWINT Flag set. This indicates that the DATA has been received, and ACK has been transmitted - call wait_for_twint - - ; Check value of TWI Status Register. Mask prescaler bits. If status different from MT_DATA_RECV go to ERROR - lds r16, TWSR - andi r16, 0xf8 - cpi r16, MT_DATA_RECV - brne error - - ; Validate that we recieved the desired data - first byte should be 0x66 - lds r16, TWDR - cpi r16, 0x66 - brne error - - ; Clear TWINT bit in TWCR to receive the next byte, this time we don't ACK - ldi r16, TWINT - sbr r16, TWEN - sts TWCR, r16 - - ; Wait for TWINT Flag set. This indicates that the DATA has been received, and NACK has been transmitted - call wait_for_twint - - ; Check value of TWI Status Register. Mask prescaler bits. If status different from MT_DATA_RECV_NACK go to ERROR - lds r16, TWSR - andi r16, 0xf8 - cpi r16, MT_DATA_RECV_NACK - brne error - - ; Validate that we recieved the desired data - second byte should be 0x77 - lds r16, TWDR - cpi r16, 0x77 - brne error - - ; Transmit STOP condition - ldi r16, TWINT - sbr r16, TWEN - sbr r16, TWSTO - sts TWCR, r16 - - ; Wait for TWINT Flag set. This indicates that the STOP condition has been sent - call wait_for_twint - - ; Check value of TWI Status Register. The masked value should be 0xf8 once done - lds r16, TWSR - andi r16, 0xf8 - cpi r16, 0xf8 - brne error - - ; Indicate success by loading 0x42 into r17 - ldi r17, 0x42 - - loop: - jmp loop - - ; Busy-waits for the TWINT flag to be set - wait_for_twint: - lds r16, TWCR - andi r16, TWINT - breq wait_for_twint - ret - - ; In case of an error, toggle a breakpoint - error: - break - `); - const cpu = new CPU(program); - const twi = new AVRTWI(cpu, twiConfig, FREQ_16MHZ); - twi.eventHandler = { - start: jest.fn(), - stop: jest.fn(), - connectToSlave: jest.fn(), - writeByte: jest.fn(), - readByte: jest.fn() - }; - - // Step 1: wait for start condition - runInstructions(cpu, twi, 4); - expect(twi.eventHandler.start).toHaveBeenCalledWith(false); - - runInstructions(cpu, twi, 16); - twi.completeStart(); - - // Step 2: wait for slave connect in read mode - runInstructions(cpu, twi, 16); - expect(twi.eventHandler.connectToSlave).toHaveBeenCalledWith(0x50, false); - - runInstructions(cpu, twi, 16); - twi.completeConnect(true); - - // Step 3: send the first byte to the master, expect ack - runInstructions(cpu, twi, 16); - expect(twi.eventHandler.readByte).toHaveBeenCalledWith(true); - - runInstructions(cpu, twi, 16); - twi.completeRead(0x66); - - // Step 4: send the first byte to the master, expect nack - runInstructions(cpu, twi, 16); - expect(twi.eventHandler.readByte).toHaveBeenCalledWith(false); - - runInstructions(cpu, twi, 16); - twi.completeRead(0x77); - - // Step 5: wait for stop condition - runInstructions(cpu, twi, 24); - expect(twi.eventHandler.stop).toHaveBeenCalled(); - - runInstructions(cpu, twi, 16); - twi.completeStop(); - - // Step 6: wait for the assembly code to indicate success by settings r17 to 0x42 - runInstructions(cpu, twi, 16); - expect(cpu.data[17]).toEqual(0x42); - }); - }); -}); |
