From a8a39ba24e36119dce48a01c2139e0e5a25674e1 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Tue, 25 Feb 2025 19:29:33 -0800 Subject: Add mailbox. --- src/mailbox.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 src/mailbox.c (limited to 'src/mailbox.c') diff --git a/src/mailbox.c b/src/mailbox.c new file mode 100644 index 0000000..eaf0955 --- /dev/null +++ b/src/mailbox.c @@ -0,0 +1,73 @@ +#include + +#include + +#include +#include + +enum +{ + MAILBOX = 0xB880 // Mailbox address relative to MMIO base address. +}; + +typedef uint32_t Message; + +static inline uint8_t msg_channel(Message msg) { + return msg & 0xf; +} + +static inline const void* msg_data(Message msg) { + // The data field is actually a pointer to the data. + return (const void*)((uintptr_t)(msg >> 4)); +} + +static inline Message msg_make(uint8_t channel, const void* data) { + return ((uintptr_t)(data) << 4) | (channel & 0xf); +} + +typedef struct Mailbox { + Message inbox; // 0x00 + uint32_t unused_1; // 0x04 + uint32_t unused_2; // 0x08 + uint32_t unused_3; // 0x0C + uint32_t unused_4; // 0x10 + uint32_t unused_5; // 0x14 + uint32_t status; // 0x18 + uint32_t unused_6; // 0x1C + Message outbox; // 0x20 +} Mailbox; + +static inline bool inbox_empty(const volatile Mailbox* pMailbox) { + return (pMailbox->status & 0x40000000) != 0; +} + +static inline bool outbox_full(const volatile Mailbox* pMailbox) { + return (pMailbox->status & 0x80000000) != 0; +} + +static volatile Mailbox* pMailbox; + +void mbox_init() { + pMailbox = mmio_get_peripheral(MAILBOX); +} + +const Mail* mbox_read(uint8_t channel) { + Message msg; + // Read until we get a message from the desired channel. + // Discard any other messages. + do { + // Wait until there is mail to receive. + while (inbox_empty(pMailbox)); + // Read the mail. + msg = pMailbox->inbox; + } while (msg_channel(msg) != channel); + return (const Mail*)(msg_data(msg)); +} + +void mbox_write(uint8_t channel, const void* mail) { + // Wait until the outbox is clear. + while (outbox_full(pMailbox)); + // Send the mail. + pMailbox->outbox = msg_make(channel, mail); +} + -- cgit v1.2.3