From ae783f1a4732881f48d24d5379d70a8a882a6e27 Mon Sep 17 00:00:00 2001 From: Alex Utter Date: Fri, 22 Oct 2021 10:55:34 -0700 Subject: [PATCH] * Added read/write functions for s8, s16, s32, and s64. (#12) * Hotfix for UART-16550 driver and Arty-Managed example design. --- doc/CHANGELOG.md | 5 +++ examples/arty_managed/create_vivado.tcl | 2 +- sim/cpp/test_io_core.cc | 26 +++++++++++ src/cpp/hal_ublaze/uart16550.cc | 7 +-- src/cpp/satcat5/io_core.cc | 59 ++++++++++++++++++++----- src/cpp/satcat5/io_core.h | 8 ++++ src/cpp/satcat5/net_core.h | 1 - src/cpp/satcat5/utils.h | 14 ++++++ 8 files changed, 105 insertions(+), 17 deletions(-) diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 49a117d..12f0b65 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -56,6 +56,11 @@ This log will be updated for each new release, but may not reflect the latest de * Reworked switch-core to allow rudimentary IGMP snooping. * Reworked switch-core to allow traffic prioritization based on EtherType. +## v2.0.1 + +* Added read/write functions for s8, s16, s32, and s64. +* Hotfix for UART-16550 driver and Arty-Managed example design. + # Copyright Notice Copyright 2019, 2020, 2021 The Aerospace Corporation diff --git a/examples/arty_managed/create_vivado.tcl b/examples/arty_managed/create_vivado.tcl index a4b0517..97d1f78 100644 --- a/examples/arty_managed/create_vivado.tcl +++ b/examples/arty_managed/create_vivado.tcl @@ -369,7 +369,7 @@ connect_bd_intf_net [get_bd_intf_ports text] [get_bd_intf_pins switch_aux_0/text # Create address segments create_bd_addr_seg -range 0x00010000 -offset 0x44A00000 \ [get_bd_addr_spaces ublaze/microblaze_0/Data] [get_bd_addr_segs ublaze/axi_uart16550_0/S_AXI/Reg] SEG_axi_uart16550_0_Reg -create_bd_addr_seg -range 0x00010000 -offset 0x44A10000 \ +create_bd_addr_seg -range 0x00100000 -offset 0x44B00000 \ [get_bd_addr_spaces ublaze/microblaze_0/Data] [get_bd_addr_segs ublaze/cfgbus_host_axi_0/CtrlAxi/CtrlAxi_addr] SEG_cfgbus_host_axi_0_CtrlAxi_addr create_bd_addr_seg -range 0x00010000 -offset 0x00000000 \ [get_bd_addr_spaces ublaze/microblaze_0/Data] [get_bd_addr_segs ublaze/ublaze_mem/dlmb_bram_if_cntlr/SLMB/Mem] SEG_dlmb_bram_if_cntlr_Mem diff --git a/sim/cpp/test_io_core.cc b/sim/cpp/test_io_core.cc index 02d7c24..f98d651 100644 --- a/sim/cpp/test_io_core.cc +++ b/sim/cpp/test_io_core.cc @@ -158,6 +158,32 @@ TEST_CASE("ArrayWrite") { } } +TEST_CASE("SignedInts") { + u8 buff[32]; + io::ArrayWrite uut(buff, sizeof(buff)); + + uut.write_s8(-123); + uut.write_s8(+123); + uut.write_s16(-12345); + uut.write_s16(+12345); + uut.write_s32(-1234567890); + uut.write_s32(+1234567890); + uut.write_s64(-1234567890123456789ll); + uut.write_s64(+1234567890123456789ll); + uut.write_finalize(); + CHECK(uut.written_len() == 30); + + io::ArrayRead rd(buff, uut.written_len()); + CHECK(rd.read_s8() == -123); + CHECK(rd.read_s8() == +123); + CHECK(rd.read_s16() == -12345); + CHECK(rd.read_s16() == +12345); + CHECK(rd.read_s32() == -1234567890); + CHECK(rd.read_s32() == +1234567890); + CHECK(rd.read_s64() == -1234567890123456789ll); + CHECK(rd.read_s64() == +1234567890123456789ll); +} + TEST_CASE("NullIO") { SECTION("NullRead") { NullRead uut; diff --git a/src/cpp/hal_ublaze/uart16550.cc b/src/cpp/hal_ublaze/uart16550.cc index adbbf6b..47b9838 100644 --- a/src/cpp/hal_ublaze/uart16550.cc +++ b/src/cpp/hal_ublaze/uart16550.cc @@ -66,7 +66,7 @@ Uart16550::Uart16550( | XUN_OPTION_RESET_TX_FIFO | XUN_OPTION_RESET_RX_FIFO; // Enable Rx-Data interrupt? - if (irq >= 0) options |= XUN_OPTION_DATA_INTR; + if (m_irq_idx >= 0) options |= XUN_OPTION_DATA_INTR; // Set hardware option flags: m_status = XUartNs550_SetOptions(&m_uart, options); if (m_status != XST_SUCCESS) return; @@ -95,7 +95,7 @@ void Uart16550::irq_event() { // Read and clear interrupt status register. u8 isr_type = (u8)XUartNs550_ReadReg(m_uart.BaseAddress, XUN_IIR_OFFSET) & XUN_INT_ID_MASK; - XUartNs550_GetLineStatusReg(m_uart.BaseAddress); + u32 linereg = XUartNs550_GetLineStatusReg(m_uart.BaseAddress); // Outgoing data ready to send? u32 txbytes = m_tx.get_peek_ready(); @@ -117,8 +117,9 @@ void Uart16550::irq_event() // Copy any new incoming data to the software buffer. // Use the three-step zero-copy-write (ZCW) method. + constexpr u32 LSR_READ_ANY = XUN_LSR_BREAK_INT | XUN_LSR_DATA_READY; u32 rxmax = m_rx.zcw_maxlen(); // Max safe to read? - if ((rxmax > 0) && (isr_type != UART_IRQ_NONE)) { + if ((rxmax > 0) && (linereg & LSR_READ_ANY)) { u8* rxtmp = m_rx.zcw_start(); // Get pointer to buffer u32 rcvd = XUartNs550_Recv(&m_uart, rxtmp, rxmax); if (rcvd) { diff --git a/src/cpp/satcat5/io_core.cc b/src/cpp/satcat5/io_core.cc index b41e9d0..e83e5f9 100644 --- a/src/cpp/satcat5/io_core.cc +++ b/src/cpp/satcat5/io_core.cc @@ -19,6 +19,9 @@ #include #include +#include + +using satcat5::util::reinterpret; void satcat5::io::Writeable::write_u8(u8 data) { @@ -59,18 +62,34 @@ void satcat5::io::Writeable::write_u64(u64 data) } else write_overflow(); } +void satcat5::io::Writeable::write_s8(s8 data) +{ + write_u8(reinterpret(data)); +} + +void satcat5::io::Writeable::write_s16(s16 data) +{ + write_u16(reinterpret(data)); +} + +void satcat5::io::Writeable::write_s32(s32 data) +{ + write_u32(reinterpret(data)); +} + +void satcat5::io::Writeable::write_s64(s64 data) +{ + write_u64(reinterpret(data)); +} + void satcat5::io::Writeable::write_f32(float data) { - union {float f; u32 u;} temp; - temp.f = data; - write_u32(temp.u); + write_u32(reinterpret(data)); } void satcat5::io::Writeable::write_f64(double data) { - union {double f; u64 u;} temp; - temp.f = data; - write_u64(temp.u); + write_u64(reinterpret(data)); } void satcat5::io::Writeable::write_bytes(unsigned nbytes, const void* src) @@ -157,18 +176,34 @@ u64 satcat5::io::Readable::read_u64() } } +s8 satcat5::io::Readable::read_s8() +{ + return reinterpret(read_u8()); +} + +s16 satcat5::io::Readable::read_s16() +{ + return reinterpret(read_u16()); +} + +s32 satcat5::io::Readable::read_s32() +{ + return reinterpret(read_u32()); +} + +s64 satcat5::io::Readable::read_s64() +{ + return reinterpret(read_u64()); +} + float satcat5::io::Readable::read_f32() { - union {float f; u32 u;} temp; - temp.u = read_u32(); - return temp.f; + return reinterpret(read_u32()); } double satcat5::io::Readable::read_f64() { - union {double f; u64 u;} temp; - temp.u = read_u64(); - return temp.f; + return reinterpret(read_u64()); } bool satcat5::io::Readable::read_bytes(unsigned nbytes, void* dst) diff --git a/src/cpp/satcat5/io_core.h b/src/cpp/satcat5/io_core.h index 1c61a45..1b0c1ff 100644 --- a/src/cpp/satcat5/io_core.h +++ b/src/cpp/satcat5/io_core.h @@ -51,6 +51,10 @@ namespace satcat5 { void write_u16(u16 data); void write_u32(u32 data); void write_u64(u64 data); + void write_s8(s8 data); + void write_s16(s16 data); + void write_s32(s32 data); + void write_s64(s64 data); void write_f32(float data); void write_f64(double data); void write_str(const char* str); @@ -107,6 +111,10 @@ namespace satcat5 { u16 read_u16(); u32 read_u32(); u64 read_u64(); + s8 read_s8(); + s16 read_s16(); + s32 read_s32(); + s64 read_s64(); float read_f32(); double read_f64(); virtual bool read_bytes(unsigned nbytes, void* dst); diff --git a/src/cpp/satcat5/net_core.h b/src/cpp/satcat5/net_core.h index 69579a1..249619c 100644 --- a/src/cpp/satcat5/net_core.h +++ b/src/cpp/satcat5/net_core.h @@ -166,7 +166,6 @@ namespace satcat5 { : m_filter(type), m_next(0) {} ~Protocol() {} - public://??? satcat5::net::Type m_filter; // Incoming packet filter private: diff --git a/src/cpp/satcat5/utils.h b/src/cpp/satcat5/utils.h index 0e26234..648118f 100644 --- a/src/cpp/satcat5/utils.h +++ b/src/cpp/satcat5/utils.h @@ -23,6 +23,7 @@ #pragma once +#include #include namespace satcat5 { @@ -193,5 +194,18 @@ namespace satcat5 { enum {SATCAT5_LITTLE_ENDIAN = 0x03020100ul, SATCAT5_BIG_ENDIAN = 0x00010203ul}; constexpr union {u8 bytes[4]; u32 value;} HOST_ORDER_CANARY = {{0,1,2,3}}; inline u32 HOST_BYTE_ORDER() {return HOST_ORDER_CANARY.value;} + + // In-place byte-for-byte format conversion, aka "type-punning". + template inline T2 reinterpret(T1 x) + { + static_assert(sizeof(T1) == sizeof(T2), "Type size mismatch"); + // Note: Using "memcpy" for type-punning is preferred safe-ish method. + // Most compilers will optimize this to a no-op, as desired. See also: + // https://gist.github.com/shafik/848ae25ee209f698763cffee272a58f8 + // https://stackoverflow.com/questions/48803363/bitwise-casting-uint32-t-to-float-in-c-c + T2 y; + std::memcpy(&y, &x, sizeof(T1)); + return y; + } } }