ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
board_usb_host.c
Go to the documentation of this file.
1
37
38#include "board_usb_host.h"
39
40#include <stdio.h>
41#include <string.h>
42
43#include "board_usb.h"
45#include "ra8_usb_regs.h"
46
47/* =============================================================================
48 * Window geometry + model sizing.
49 * =============================================================================
50 */
51
53typedef enum : uint64_t {
54 k_usbhs_base = 0x40351000UL,
55 k_usbhs_span = 0x104UL,
56 k_usbhs_reg_words = 0x104UL / 2U,
60
62typedef enum : uint16_t {
66
68typedef enum : uint16_t {
76
78typedef enum : uint16_t {
82
84typedef enum : uint16_t {
86 k_usbhs_dcp_bit = 0x0001U,
90
92typedef enum : uint32_t {
95
97typedef enum : uint16_t {
102
103/* =============================================================================
104 * Model state.
105 * =============================================================================
106 */
107
117typedef struct {
118 uint16_t reg[k_usbhs_reg_words];
124 uint16_t stage_len;
125 uint16_t rhst;
126 bool engaged;
127 bool allowed;
132 uint32_t setups;
133 uint32_t bulk_out;
134 uint32_t bulk_in;
136
148
157static bool s_hs_trace;
158
159/* =============================================================================
160 * Small helpers.
161 * =============================================================================
162 */
163
175RA8_INTERNAL static uint32_t internal_usbhs_word(uint64_t off)
176{
177 return (uint32_t)((off & ~(uint64_t)1U) / 2U);
178}
179
191{
192 const uint16_t sel = s_hs.reg[internal_usbhs_word((uint64_t)k_ra8_usb_off_cfifosel)];
193 return (uint8_t)(sel & (uint16_t)k_ra8_fifosel_curpipe);
194}
195
207{
208 const uint16_t sel = s_hs.reg[internal_usbhs_word((uint64_t)k_ra8_usb_off_cfifosel)];
209 return (sel & (uint16_t)k_ra8_fifosel_isel) != 0U;
210}
211
223RA8_INTERNAL static uint8_t internal_usbhs_pipe_ep(uint8_t pipe)
224{
225 const uint8_t ep =
226 (uint8_t)(s_hs.pipecfg[pipe % k_ra8_usb_pipe_count] & (uint16_t)k_ra8_pipecfg_epnum_mask);
227 return (ep != 0U) ? ep : pipe; /* unconfigured: fall back to pipe == EP. */
228}
229
242{
243 return (s_hs.pipecfg[pipe % k_ra8_usb_pipe_count] & (uint16_t)k_ra8_pipecfg_dir_in) != 0U;
244}
245
257RA8_INTERNAL static uint16_t internal_usbhs_pipe_mps(uint8_t pipe)
258{
259 const uint16_t mps =
260 (uint16_t)(s_hs.pipemaxp[pipe % k_ra8_usb_pipe_count] & (uint16_t)k_usbhs_pipemaxp_mxps);
261 return (mps != 0U) ? mps : (uint16_t)k_usbhs_mps_fall;
262}
263
275{
276 const uint16_t mps = (uint16_t)(s_hs.reg[internal_usbhs_word((uint64_t)k_ra8_usb_off_dcpmaxp)] &
277 (uint16_t)k_usbhs_dcpmaxp_mxps);
278 return (mps != 0U) ? mps : (uint16_t)k_usbhs_mps_fall;
279}
280
281/* =============================================================================
282 * Bus transactions (loop-cable forwarding).
283 * =============================================================================
284 */
285
304RA8_INTERNAL static void internal_usbhs_do_setup(uc_engine* uc)
305{
306 s_hs.last_setup_in = false;
307 s_hs.sie_status_done = false;
308 s_hs.ccpl_armed = false;
309 s_hs.status_zlp = false;
310 const uint32_t w1 = internal_usbhs_word((uint64_t)k_ra8_usb_off_intsts1);
312 s_hs.reg[w1] = (uint16_t)(s_hs.reg[w1] | (uint16_t)k_usbhs_int1_sign);
313 return;
314 }
315 const uint16_t req = s_hs.reg[internal_usbhs_word((uint64_t)k_ra8_usb_off_usbreq)];
316 const uint16_t val = s_hs.reg[internal_usbhs_word((uint64_t)k_ra8_usb_off_usbval)];
317 const uint16_t indx = s_hs.reg[internal_usbhs_word((uint64_t)k_ra8_usb_off_usbindx)];
318 const uint16_t leng = s_hs.reg[internal_usbhs_word((uint64_t)k_ra8_usb_off_usbleng)];
319 s_hs.last_setup_in = ((req & (uint16_t)k_usbhs_setup_dir_in) != 0U);
320 s_hs.sie_status_done = board_usb_loop_setup(uc, req, val, indx, leng);
321 s_hs.reg[w1] = (uint16_t)(s_hs.reg[w1] | (uint16_t)k_usbhs_int1_sack);
322 s_hs.setups++;
323 if (s_hs_trace) {
324 (void)priv_emu_io_errf(" USBHS host : SETUP req=0x%04X wVal=0x%04X wLen=%u%s\n",
325 (unsigned)req,
326 (unsigned)val,
327 (unsigned)leng,
328 s_hs.sie_status_done ? " (SIE status)" : "");
329 }
330}
331
352RA8_INTERNAL static void internal_usbhs_do_ccpl(uc_engine* uc)
353{
354 const uint32_t wb = internal_usbhs_word((uint64_t)k_ra8_usb_off_bempsts);
355 if (s_hs.last_setup_in) {
357 s_hs.reg[wb] = (uint16_t)(s_hs.reg[wb] | (uint16_t)k_usbhs_dcp_bit);
358 return;
359 }
360 if (s_hs.sie_status_done) {
361 s_hs.status_zlp = true; /* SET_ADDRESS: the SIE completed the transfer. */
362 return;
363 }
364 s_hs.ccpl_armed = true; /* status ZLP follows the device firmware's CCPL. */
365}
366
387RA8_INTERNAL static uint16_t internal_usbhs_brdysts_value(uc_engine* uc)
388{
389 if (s_hs.ccpl_armed && board_usb_loop_take_ccpl(uc)) {
390 s_hs.ccpl_armed = false;
391 s_hs.status_zlp = true;
392 }
393 uint16_t v = 0U;
394 if (s_hs.status_zlp || (board_usb_loop_ctrl_in_avail() > 0U)) {
395 v |= (uint16_t)k_usbhs_dcp_bit;
396 }
397 for (uint8_t pipe = 1U; pipe < (uint8_t)k_ra8_usb_pipe_count; pipe++) {
398 if (s_hs.pipecfg[pipe] == 0U) {
399 continue;
400 }
401 if (internal_usbhs_pipe_is_tx(pipe)) {
402 continue;
403 }
405 v = (uint16_t)(v | (uint16_t)(1U << pipe));
406 }
407 }
408 return v;
409}
410
431{
432 const uint8_t pipe = internal_usbhs_cur_pipe();
433 uint16_t avail = 0U;
434 uint16_t mps = (uint16_t)k_usbhs_mps_fall;
435 if (pipe == 0U) {
439 }
440 } else if (!internal_usbhs_pipe_is_tx(pipe)) {
442 mps = internal_usbhs_pipe_mps(pipe);
443 } else {
444 avail = 0U;
445 }
446 const uint16_t dtln = (avail < mps) ? avail : mps;
447 return (uint16_t)((uint16_t)k_ra8_fifoctr_frdy | (dtln & (uint16_t)k_ra8_fifoctr_dtln));
448}
449
469RA8_INTERNAL static uint64_t internal_usbhs_cfifo_read(uc_engine* uc, unsigned size)
470{
471 uint8_t bytes[sizeof(uint32_t)] = {};
472 const uint16_t cap = (size < sizeof(bytes)) ? (uint16_t)size : (uint16_t)sizeof(bytes);
473 const uint8_t pipe = internal_usbhs_cur_pipe();
474 uint16_t got = 0U;
475 if (pipe == 0U) {
476 got = board_usb_loop_ctrl_in_read(bytes, cap);
477 } else if (!internal_usbhs_pipe_is_tx(pipe)) {
478 got = board_usb_loop_bulk_in_read(uc, internal_usbhs_pipe_ep(pipe), bytes, cap);
479 if (got > 0U) {
480 s_hs.bulk_in++;
481 }
482 } else {
483 got = 0U;
484 }
485 (void)got; /* short reads leave the upper packed bytes zero (don't-care). */
486 uint64_t v = 0U;
487 for (uint32_t i = 0U; i < (uint32_t)cap; i++) {
488 v |= ((uint64_t)bytes[i]) << (i * (uint32_t)k_usbhs_byte_bits);
489 }
490 return v;
491}
492
510RA8_INTERNAL static void internal_usbhs_cfifo_write(uint64_t value, unsigned size)
511{
512 for (uint32_t i = 0U; (i < size) && (s_hs.stage_len < (uint16_t)k_usbhs_stage_cap); i++) {
513 s_hs.stage[s_hs.stage_len] =
514 (uint8_t)((value >> (i * (uint32_t)k_usbhs_byte_bits)) & (uint64_t)k_usbhs_byte_mask);
515 s_hs.stage_len++;
516 }
517}
518
541RA8_INTERNAL static void internal_usbhs_cfifoctr_write(uc_engine* uc, uint16_t value)
542{
543 const uint8_t pipe = internal_usbhs_cur_pipe();
544 if ((value & (uint16_t)k_ra8_fifoctr_bclr) != 0U) {
545 if (pipe == 0U) {
547 s_hs.stage_len = 0U;
548 } else {
550 s_hs.status_zlp = false;
551 }
552 } else if (internal_usbhs_pipe_is_tx(pipe)) {
553 s_hs.stage_len = 0U;
554 } else {
556 }
557 }
558 if ((value & (uint16_t)k_ra8_fifoctr_bval) != 0U) {
559 const uint32_t wb = internal_usbhs_word((uint64_t)k_ra8_usb_off_bempsts);
560 if ((pipe == 0U) && internal_usbhs_cfifo_isel() && (s_hs.stage_len > 0U)) {
561 board_usb_loop_ctrl_out(uc, s_hs.stage, s_hs.stage_len);
562 s_hs.reg[wb] = (uint16_t)(s_hs.reg[wb] | (uint16_t)k_usbhs_dcp_bit);
563 s_hs.stage_len = 0U;
564 } else if ((pipe != 0U) && (s_hs.stage_len > 0U)) {
565 board_usb_loop_bulk_out(uc, internal_usbhs_pipe_ep(pipe), s_hs.stage, s_hs.stage_len);
566 s_hs.reg[wb] = (uint16_t)(s_hs.reg[wb] | (uint16_t)(1U << pipe));
567 s_hs.stage_len = 0U;
568 s_hs.bulk_out++;
569 }
570 }
571}
572
591RA8_INTERNAL static void internal_usbhs_dvstctr_write(uc_engine* uc, uint16_t value)
592{
593 const uint32_t w = internal_usbhs_word((uint64_t)k_ra8_usb_off_dvstctr0);
594 const uint16_t old = s_hs.reg[w];
595 s_hs.reg[w] = (uint16_t)(value & (uint16_t)~(uint16_t)k_usbhs_rhst_mask);
596 const bool was_rst = (old & (uint16_t)k_usbhs_dvst_usbrst) != 0U;
597 const bool is_rst = (value & (uint16_t)k_usbhs_dvst_usbrst) != 0U;
598 if (was_rst && !is_rst) {
600 s_hs.rhst = (uint16_t)k_usbhs_dvst_rhst_fs;
602 } else {
603 s_hs.rhst = 0U;
604 }
605 }
606}
607
626RA8_INTERNAL static void internal_usbhs_dcpctr_write(uc_engine* uc, uint16_t value)
627{
628 const uint32_t w = internal_usbhs_word((uint64_t)k_ra8_usb_off_dcpctr);
629 const uint16_t old = s_hs.reg[w];
630 if (((value & (uint16_t)k_usbhs_dcpctr_sureq) != 0U) &&
631 ((old & (uint16_t)k_usbhs_dcpctr_sureq) == 0U)) {
633 }
634 if (((value & (uint16_t)k_usbhs_dcpctr_ccpl) != 0U) &&
635 ((old & (uint16_t)k_usbhs_dcpctr_ccpl) == 0U)) {
637 }
638 s_hs.reg[w] = (uint16_t)(value & (uint16_t)~(uint16_t)((uint16_t)k_usbhs_ctr_pulse_mask |
639 (uint16_t)k_usbhs_dcpctr_sureqclr));
640}
641
642/* =============================================================================
643 * Engaged read / write dispatch.
644 * =============================================================================
645 */
646
668RA8_INTERNAL static uint64_t internal_usbhs_reg_read(uc_engine* uc, uint64_t off, unsigned size)
669{
670 const uint8_t sel = (uint8_t)(s_hs.reg[internal_usbhs_word((uint64_t)k_ra8_usb_off_pipesel)] &
671 (uint16_t)k_ra8_fifosel_curpipe);
672 switch ((uint16_t)off) {
673 case (uint16_t)k_ra8_usb_off_syssts0:
674 return (board_usb_loop_attached()) ? (uint64_t)k_usbhs_lnst_j_state : 0U;
675 case (uint16_t)k_ra8_usbhs_off_pllsta:
676 return (uint16_t)k_ra8_pllsta_plllock;
677 case (uint16_t)k_ra8_usb_off_dvstctr0:
678 return (uint16_t)(s_hs.reg[internal_usbhs_word(off)] | s_hs.rhst);
679 case (uint16_t)k_ra8_usb_off_cfifo:
680 return internal_usbhs_cfifo_read(uc, size); /* full width: 32-bit MBW drains. */
681 case (uint16_t)k_ra8_usb_off_cfifoctr:
683 case (uint16_t)k_ra8_usb_off_brdysts:
685 case (uint16_t)k_ra8_usb_off_nrdysts:
686 return 0U;
687 case (uint16_t)k_ra8_usb_off_pipecfg:
688 return s_hs.pipecfg[sel % k_ra8_usb_pipe_count];
689 case (uint16_t)k_ra8_usb_off_pipebuf:
690 return s_hs.pipebuf[sel % k_ra8_usb_pipe_count];
691 case (uint16_t)k_ra8_usb_off_pipemaxp:
692 return s_hs.pipemaxp[sel % k_ra8_usb_pipe_count];
693 case (uint16_t)k_ra8_usb_off_pipeperi:
694 return s_hs.pipeperi[sel % k_ra8_usb_pipe_count];
695 default:
696 return s_hs.reg[internal_usbhs_word(off)];
697 }
698}
699
722RA8_INTERNAL static void
723internal_usbhs_reg_write(uc_engine* uc, uint64_t off, unsigned size, uint64_t value64)
724{
725 const uint16_t value = (uint16_t)value64;
726 const uint8_t sel = (uint8_t)(s_hs.reg[internal_usbhs_word((uint64_t)k_ra8_usb_off_pipesel)] &
727 (uint16_t)k_ra8_fifosel_curpipe);
728 /* The CFIFO port spans +0x14..+0x17: 32-bit head words at +0x14, the
729 * CFIFOH (+0x16) / CFIFOHH (+0x17) residual aliases for the 2- / 1-byte
730 * tails. All append to the same OUT staging. */
731 if ((off >= (uint64_t)k_ra8_usb_off_cfifo) && (off < (uint64_t)(k_ra8_usb_off_cfifo + 4U))) {
732 internal_usbhs_cfifo_write(value64, size); /* full width: 32-bit MBW fills. */
733 return;
734 }
735 switch ((uint16_t)off) {
736 case (uint16_t)k_ra8_usb_off_cfifoctr:
738 return;
739 case (uint16_t)k_ra8_usb_off_dcpctr:
741 return;
742 case (uint16_t)k_ra8_usb_off_dvstctr0:
744 return;
745 case (uint16_t)k_ra8_usb_off_intsts1:
746 case (uint16_t)k_ra8_usb_off_bempsts:
747 /* W0C: a written 0 clears, a written 1 preserves. */
748 s_hs.reg[internal_usbhs_word(off)] &= value;
749 return;
750 case (uint16_t)k_ra8_usb_off_brdysts:
751 /* Live bits are composed; only the sticky status-ZLP flag is W0C. */
752 if ((value & (uint16_t)k_usbhs_dcp_bit) == 0U) {
753 s_hs.status_zlp = false;
754 }
755 return;
756 case (uint16_t)k_ra8_usb_off_nrdysts:
757 return; /* never latched -- nothing to clear. */
758 case (uint16_t)k_ra8_usb_off_pipecfg:
759 s_hs.pipecfg[sel % k_ra8_usb_pipe_count] = value;
760 return;
761 case (uint16_t)k_ra8_usb_off_pipebuf:
762 s_hs.pipebuf[sel % k_ra8_usb_pipe_count] = value;
763 return;
764 case (uint16_t)k_ra8_usb_off_pipemaxp:
765 s_hs.pipemaxp[sel % k_ra8_usb_pipe_count] = value;
766 return;
767 case (uint16_t)k_ra8_usb_off_pipeperi:
768 s_hs.pipeperi[sel % k_ra8_usb_pipe_count] = value;
769 return;
770 default:
771 break;
772 }
773 if ((off >= (uint64_t)k_ra8_usb_off_pipectr) &&
774 (off < (uint64_t)(k_ra8_usb_off_pipectr +
775 ((uint64_t)k_ra8_usb_pipectr_count * sizeof(uint16_t))))) {
776 /* PIPECTR: PID persists; the SQSET / SQCLR pulses never store. */
777 s_hs.reg[internal_usbhs_word(off)] =
778 (uint16_t)(value & (uint16_t)~(uint16_t)k_usbhs_ctr_pulse_mask);
779 return;
780 }
781 s_hs.reg[internal_usbhs_word(off)] = value;
782}
783
784/* =============================================================================
785 * Public lifecycle + MMIO entry points.
786 * =============================================================================
787 */
788
789void board_usb_host_init(bool trace)
790{
791 s_hs = (usbhs_state_t){};
792 s_hs_trace = trace;
793}
794
796{
797 s_hs.allowed = allowed;
798}
799
800uint64_t board_usb_host_read(uc_engine* uc, uint64_t addr, unsigned size, bool* handled)
801{
802 if (!s_hs.engaged || (addr < (uint64_t)k_usbhs_base) ||
803 (addr >= ((uint64_t)k_usbhs_base + (uint64_t)k_usbhs_span))) {
804 *handled = false;
805 return 0U;
806 }
807 *handled = true;
808 return internal_usbhs_reg_read(uc, addr - (uint64_t)k_usbhs_base, size);
809}
810
811void board_usb_host_write(uc_engine* uc,
812 uint64_t addr,
813 unsigned size,
814 uint64_t value,
815 bool* handled)
816{
817 if ((addr < (uint64_t)k_usbhs_base) ||
818 (addr >= ((uint64_t)k_usbhs_base + (uint64_t)k_usbhs_span))) {
819 *handled = false;
820 return;
821 }
822 const uint64_t off = addr - (uint64_t)k_usbhs_base;
823 if (!s_hs.engaged) {
824 /* Dormant: watch only the SYSCFG host-role select. The write still
825 * reports unhandled so the sparse fallback records it and every app that
826 * never engages keeps its exact current behaviour. */
827 *handled = false;
828 if (s_hs.allowed && (off == (uint64_t)k_ra8_usb_off_syscfg) &&
829 (((uint16_t)value & (uint16_t)(1U << k_ra8_syscfg_bit_dcfm)) != 0U)) {
830 s_hs.engaged = true;
831 s_hs.reg[internal_usbhs_word((uint64_t)k_ra8_usb_off_syscfg)] = (uint16_t)value;
833 (void)priv_emu_io_errf(
834 " USBHS host : host mode engaged (SYSCFG.DCFM) -- self-loop to USBFS\n");
835 *handled = true;
836 }
837 return;
838 }
839 *handled = true;
840 internal_usbhs_reg_write(uc, off, size, value);
841}
842
844{
845 if (!s_hs.engaged) {
846 return;
847 }
848 (void)priv_emu_io_errf(
849 " USBHS host : %u SETUP(s), %u bulk-OUT commit(s), %u bulk-IN drain(s)\n",
850 s_hs.setups,
851 s_hs.bulk_out,
852 s_hs.bulk_in);
853}
@ k_usbhs_byte_mask
One-byte mask.
@ k_usbhs_byte_bits
Bits per byte.
@ k_usbhs_setup_dir_in
bmRequestType device-to-host bit (USB 2.0 9.3).
static usbhs_state_t s_hs
@ k_usbhs_dcp_bit
BRDYSTS/BEMPSTS/NRDYSTS DCP (pipe 0) bit.
usbhs_geom_t
USBHS host register-window geometry and staging-buffer caps.
@ k_usbhs_base
USBHS base (HUM Ch 37, p 2059).
@ k_usbhs_span
Modelled window (covers DEVADD / LPSTS).
USBFS controller model + a virtual USB host for the board emulator.
void board_usb_loop_bulk_in_flush(uint8_t ep)
Drop whatever remains of a device pipe's bulk-IN staging.
bool board_usb_loop_take_ccpl(uc_engine *uc)
Poll the device's control-transfer completion (DCPCTR.CCPL).
void board_usb_loop_ctrl_out(uc_engine *uc, const uint8_t *data, uint16_t len)
Deliver a control-OUT data-stage packet to the device's DCP.
bool board_usb_loop_attached(void)
Whether the modelled USBFS device presents its D+ pull-up.
void board_usb_loop_bulk_out(uc_engine *uc, uint8_t ep, const uint8_t *data, uint16_t len)
Deliver one bulk-OUT packet from the firmware host to a device pipe.
uint16_t board_usb_loop_ctrl_in_avail(void)
Control-IN bytes the device has queued and the host not yet drained.
uint16_t board_usb_loop_ctrl_in_read(uint8_t *dst, uint16_t cap)
Drain up to cap control-IN bytes from the device's DCP staging.
void board_usb_loop_latch(void)
Latch the self-loop: the firmware brought a controller up as HOST.
uint16_t board_usb_loop_bulk_in_read(uc_engine *uc, uint8_t ep, uint8_t *dst, uint16_t cap)
Drain up to cap bulk-IN bytes from a device pipe's staging.
void board_usb_loop_status_out_zlp(uc_engine *uc)
Run the control-read status stage against the device (host OUT ZLP).
bool board_usb_loop_setup(uc_engine *uc, uint16_t req, uint16_t val, uint16_t indx, uint16_t leng)
Deliver one SETUP packet from the firmware host to the device.
void board_usb_loop_bus_reset(uc_engine *uc)
Deliver a bus reset to the modelled USBFS device (host released RST).
void board_usb_loop_ctrl_in_flush(void)
Drop whatever remains of the device's control-IN staging.
uint16_t board_usb_loop_bulk_in_avail(uint8_t ep)
Bulk-IN bytes a device pipe has queued and the host not yet drained.
usbhs_pulse_t
DCPCTR / PIPECTR write-pulse bits that never persist in a shadow.
@ k_usbhs_ctr_sqclr
SQCLR: force DATA0 (pulse).
@ k_usbhs_dcpctr_ccpl
CCPL: run the status stage.
@ k_usbhs_ctr_pulse_mask
SUREQ | SQCLR | SQSET (never stored).
@ k_usbhs_dcpctr_sureqclr
SUREQCLR: abort a SETUP (pulse).
@ k_usbhs_dcpctr_sureq
SUREQ: launch the SETUP (pulse).
@ k_usbhs_ctr_sqset
SQSET: force DATA1 (pulse).
static void internal_usbhs_cfifoctr_write(uc_engine *uc, uint16_t value)
Apply a CFIFOCTR write: BCLR discards, BVAL commits over the loop.
void board_usb_host_report(void)
Print the USBHS host-model section of the end-of-run summary.
static void internal_usbhs_dvstctr_write(uc_engine *uc, uint16_t value)
Apply a DVSTCTR0 write: bus-reset delivery + RHST latch.
static void internal_usbhs_dcpctr_write(uc_engine *uc, uint16_t value)
Apply a DCPCTR write: PID persists, SUREQ / CCPL pulses execute.
static bool internal_usbhs_cfifo_isel(void)
True when CFIFOSEL selects the write (ISEL) side of the DCP port.
usbhs_bits_t
SETUP-word decode + status-bit constants for the host model.
@ k_usbhs_lnst_j_state
SYSSTS0.LNST: J-state (FS idle).
static void internal_usbhs_do_setup(uc_engine *uc)
Run the SETUP transaction the firmware host launched with SUREQ.
static void internal_usbhs_reg_write(uc_engine *uc, uint64_t off, unsigned size, uint64_t value64)
Write one USBHS register (engaged path).
void board_usb_host_write(uc_engine *uc, uint64_t addr, unsigned size, uint64_t value, bool *handled)
Dispatch an MMIO write inside the USBHS register window.
static uint32_t internal_usbhs_word(uint64_t off)
Word index into the 16-bit register shadow for a window offset.
static uint8_t internal_usbhs_pipe_ep(uint8_t pipe)
Device endpoint number a host pipe addresses (PIPECFG.EPNUM).
static uint64_t internal_usbhs_reg_read(uc_engine *uc, uint64_t off, unsigned size)
Read one USBHS register (engaged path).
static bool internal_usbhs_pipe_is_tx(uint8_t pipe)
True when a host pipe transmits (host-to-device; PIPECFG.DIR set).
static uint16_t internal_usbhs_dcp_mps(void)
The DCP's effective max packet size (fallback when unprogrammed).
static void internal_usbhs_do_ccpl(uc_engine *uc)
Run the status stage the firmware host launched with CCPL.
static bool s_hs_trace
When true, each loop-cable transaction is logged to injected error sink.
usbhs_int1_t
INTSTS1 host-event bits the model latches (HUM Ch 37.2.15).
@ k_usbhs_int1_sack
SACK: the device ACKed the SETUP.
@ k_usbhs_int1_sign
SIGN: three SETUP attempts failed.
static uint16_t internal_usbhs_pipe_mps(uint8_t pipe)
A pipe's effective max packet size (fallback when unprogrammed).
static uint16_t internal_usbhs_brdysts_value(uc_engine *uc)
Compose the live BRDYSTS value (and poll the device's CCPL).
static void internal_usbhs_cfifo_write(uint64_t value, unsigned size)
Append CFIFO data-port write bytes to the OUT staging buffer.
uint64_t board_usb_host_read(uc_engine *uc, uint64_t addr, unsigned size, bool *handled)
Dispatch an MMIO read inside the USBHS register window.
usbhs_dvst_t
DVSTCTR0 fields the model owns (HUM Ch 37.2.5).
@ k_usbhs_dvst_usbrst
USBRST: bus-reset signalling.
@ k_usbhs_dvst_rhst_fs
RHST = 10b: full-speed link.
static uint16_t internal_usbhs_cfifoctr_value(void)
CFIFOCTR read value: FRDY plus the receive-side DTLN.
usbhs_field_t
Register field masks (HUM Ch 37.2) not exported by ra8_usb_regs.h.
@ k_usbhs_rhst_mask
DVSTCTR0.RHST: connected-speed (RO).
@ k_usbhs_pipemaxp_mxps
PIPEMAXP.MXPS: pipe max packet field.
@ k_usbhs_dcpmaxp_mxps
DCPMAXP.MXPS: DCP max packet field.
static uint64_t internal_usbhs_cfifo_read(uc_engine *uc, unsigned size)
Service a CFIFO data-port read: drain receive bytes, packed LE.
usbhs_misc_t
Small integer constants (shifts / offsets) used by the model.
void board_usb_host_set_allowed(bool allowed)
Grant (or deny) the register-level loop for this firmware.
@ k_usbhs_reg_words
16-bit register shadow word count.
@ k_usbhs_mps_fall
DTLN clamp when no MPS is programmed.
@ k_usbhs_stage_cap
OUT staging (one HS bulk packet).
void board_usb_host_init(bool trace)
Reset the USBHS host-mode model to its power-on state.
static uint8_t internal_usbhs_cur_pipe(void)
Currently-selected CFIFO pipe number (CFIFOSEL.CURPIPE[3:0]).
USBHS HOST-mode controller model (self-loop peer of the USBFS device).
Bounded raw-descriptor I/O seam for the RA8 emulator.
emu_io_result_t priv_emu_io_errf(const char *format,...)
Format bounded text and write it to the injected error descriptor.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
USB Full-Speed + High-Speed controller layout for the Renesas RA8D2.
@ k_ra8_pllsta_plllock
b0 : PHY PLL locked flag.
@ k_ra8_syscfg_bit_dcfm
1 = host mode, 0 = device.
@ k_ra8_usb_off_pipecfg
PIPECFG : Selected pipe cfg.
@ k_ra8_usb_off_pipectr
PIPECTR : PIPE1..9 control.
@ k_ra8_usb_off_syssts0
SYSSTS0 : System status 0.
@ k_ra8_usb_off_usbleng
USBLENG : USB request wLength.
@ k_ra8_usb_off_dvstctr0
DVSTCTR0 : Device state ctrl.
@ k_ra8_usb_off_usbindx
USBINDX : USB request wIndex.
@ k_ra8_usb_off_nrdysts
NRDYSTS : NRDY Status.
@ k_ra8_usb_off_pipebuf
PIPEBUF : Selected pipe buf.
@ k_ra8_usb_off_usbval
USBVAL : USB request wValue.
@ k_ra8_usb_off_cfifosel
CFIFOSEL : Control FIFO select.
@ k_ra8_usb_off_bempsts
BEMPSTS : BEMP Status.
@ k_ra8_usb_off_intsts1
INTSTS1 : Interrupt Status 1.
@ k_ra8_usb_off_pipeperi
PIPEPERI : Selected pipe period.
@ k_ra8_usb_off_dcpmaxp
DCPMAXP : DCP max packet.
@ k_ra8_usb_off_cfifo
CFIFO : Control FIFO port.
@ k_ra8_usb_off_dcpctr
DCPCTR : DCP control.
@ k_ra8_usb_off_usbreq
USBREQ : USB request type.
@ k_ra8_usb_off_pipemaxp
PIPEMAXP : Selected pipe maxp.
@ k_ra8_usb_off_brdysts
BRDYSTS : BRDY Status.
@ k_ra8_usb_off_pipesel
PIPESEL : Pipe window select.
@ k_ra8_usb_off_cfifoctr
CFIFOCTR : Control FIFO control.
@ k_ra8_usb_off_syscfg
SYSCFG : System config.
@ k_ra8_fifoctr_frdy
FIFO ready.
@ k_ra8_fifoctr_bclr
Buffer clear.
@ k_ra8_fifoctr_dtln
Data length (write-bytes-rem).
@ k_ra8_fifoctr_bval
Buffer valid.
@ k_ra8_fifosel_isel
CFIFO direction (DCP only).
@ k_ra8_fifosel_curpipe
Current pipe select [3:0].
@ k_ra8_pipecfg_epnum_mask
Endpoint number [3:0].
@ k_ra8_pipecfg_dir_in
1 = IN, 0 = OUT (peri).
@ k_ra8_usb_pipectr_count
PIPECTR[9] = PIPE1..PIPE9.
@ k_ra8_usb_pipe_count
DCP (pipe 0) + PIPE1..PIPE9.
@ k_ra8_usbhs_off_pllsta
PLLSTA : PLL lock flag.
Aggregate USBHS host-controller model state.
uint16_t rhst
DVSTCTR0.RHST after bus reset.
uint16_t stage_len
Staged OUT bytes.
uint32_t bulk_out
Bulk-OUT packets delivered.
uint16_t pipeperi[k_ra8_usb_pipe_count]
Windowed PIPEPERI per pipe.
uint8_t stage[k_usbhs_stage_cap]
CFIFO OUT staging buffer.
bool last_setup_in
Last SETUP was device-to-host.
bool status_zlp
Status ZLP ready for the host.
uint16_t pipemaxp[k_ra8_usb_pipe_count]
Windowed PIPEMAXP per pipe.
bool ccpl_armed
Awaiting the device's CCPL.
bool engaged
Model owns the window.
bool allowed
main.c granted the loop.
uint32_t bulk_in
Bulk-IN packets collected.
uint32_t setups
SETUP packets bridged to the device.
bool sie_status_done
SIE ran the status (SET_ADDR).
uint16_t pipecfg[k_ra8_usb_pipe_count]
Windowed PIPECFG per pipe.
uint16_t pipebuf[k_ra8_usb_pipe_count]
Windowed PIPEBUF per pipe.