
// ****************************************************************************
//
//                                 Main code
//
// ****************************************************************************
// This app shows the effect of byte and halfword writes on IO registers. All
// IO registers on RP2040 will sample the entire 32 bit write data bus on any
// write; the transfer size and the 2 LSBs of the address are *ignored*.
//
// This can have unintuitive results, especially given the way RP2040
// busmasters replicate narrow write data across the entire 32-bit write data
// bus. However, this behaviour can be quite useful if you are aware of it!

/*
Debug output
------------
Writing 32 bit value
Should be 0xdeadbeef: 0xdeadbeef

Reading back 1 byte at a time
Should be ef be ad de: ef be ad de

Writing 8 bit value 0xa5 at offset 0
Should be 0xa5a5a5a5: 0xa5a5a5a5

Writing 8 bit value at offset 1
Should be 0x3c3c3c3c: 0x3c3c3c3c

Writing 16 bit value at offset 0
Should be 0xf00df00d: 0xf00df00d
*/

#include "include.h"

int main()
{
	stdio_init_all();

	// wait to connect terminal
	int c;
	do {
		printf("Press spacebar to start...\n");
		c = getchar();
	} while (c != ' ');

	// We'll use WATCHDOG_SCRATCH0 as a convenient 32 bit read/write register
	// that we can assign arbitrary values to
	io_rw_32 *scratch32 = &watchdog_hw->scratch[0];
	// Alias the scratch register as two halfwords at offsets +0x0 and +0x2
	volatile uint16_t *scratch16 = (volatile uint16_t *) scratch32;
	// Alias the scratch register as four bytes at offsets +0x0, +0x1, +0x2, +0x3:
	volatile uint8_t *scratch8 = (volatile uint8_t *) scratch32;

	// Show that we can read/write the scratch register as normal:
	printf("Writing 32 bit value\n");
	*scratch32 = 0xdeadbeef;
	printf("Should be 0xdeadbeef: 0x%08x\n", *scratch32);

	// We can do narrow reads just fine -- IO registers treat this as a 32 bit
	// read, and the processor/DMA will pick out the correct byte lanes based
	// on transfer size and address LSBs
	printf("\nReading back 1 byte at a time\n");
	// Little-endian!
	printf("Should be ef be ad de: %02x %02x %02x %02x\n",
		scratch8[0], scratch8[1], scratch8[2], scratch8[3]);

	// The Cortex-M0+ and the RP2040 DMA replicate byte writes across the bus,
	// and IO registers will sample the entire write bus always.
	printf("\nWriting 8 bit value 0xa5 at offset 0\n");
	scratch8[0] = 0xa5;
	// Read back the whole scratch register in one go
	printf("Should be 0xa5a5a5a5: 0x%08x\n", *scratch32);

	// The IO register ignores the address LSBs [1:0] as well as the transfer
	// size, so it doesn't matter what byte offset we use
	printf("\nWriting 8 bit value at offset 1\n");
	scratch8[1] = 0x3c;
	printf("Should be 0x3c3c3c3c: 0x%08x\n", *scratch32);

	// Halfword writes are also replicated across the write data bus
	printf("\nWriting 16 bit value at offset 0\n");
	scratch16[0] = 0xf00d;
	printf("Should be 0xf00df00d: 0x%08x\n", *scratch32);

	// Wait for uart output to finish
	sleep_ms(100);
}
