From 25be6a92a9280e73ae9eba58357dded8817c402f Mon Sep 17 00:00:00 2001 From: dwf1m12 <d.w.flynn@soton.ac.uk> Date: Thu, 31 Mar 2022 11:15:49 +0100 Subject: [PATCH] New ADP controller integrated in place of PL230 with testbench support --- .../Device/ARM/CMSDK_CM0/Include/CMSDK_CM0.h | 13 +- .../software/common/bootloader/bootloader.c | 2 +- .../systems/cortex_m0_mcu/rtl_sim/adp.cmd | 15 + .../systems/cortex_m0_mcu/verilog/bootrom.v | 216 +-- .../verilog/cmsdk_apb_uart_streamio.v | 1157 +++++++++++++++++ .../verilog/cmsdk_ft1248x1_adpio.v | 157 +++ .../systems/cortex_m0_mcu/verilog/cmsdk_mcu.v | 186 ++- .../cortex_m0_mcu/verilog/cmsdk_mcu_chip.v | 272 ++-- .../cortex_m0_mcu/verilog/cmsdk_mcu_system.v | 57 +- .../verilog/cmsdk_uart_capture.v | 2 +- .../cortex_m0_mcu/verilog/tb_cmsdk_mcu.v | 56 +- .../cortex_m0_mcu/verilog/tbench_M0.vc | 9 +- IPLIB/ADPcontrol_v1_0/ADPcontrol_v1_0.v | 103 ++ IPLIB/ADPcontrol_v1_0/ADPmanager.v | 786 +++++++++++ .../ft1248_1bit_testbench.v | 285 ++++ .../ft1248_streamio_v1_0.v | 305 +++++ IPLIB/axi_stream_io_v1_0/axi_stream_io_v1_0.v | 114 ++ .../axi_stream_io_v1_0_axi_s.v | 424 ++++++ 18 files changed, 3917 insertions(+), 242 deletions(-) create mode 100644 Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/rtl_sim/adp.cmd create mode 100644 Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/cmsdk_apb_uart_streamio.v create mode 100644 Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/cmsdk_ft1248x1_adpio.v create mode 100755 IPLIB/ADPcontrol_v1_0/ADPcontrol_v1_0.v create mode 100755 IPLIB/ADPcontrol_v1_0/ADPmanager.v create mode 100644 IPLIB/FT1248_streamio_v1_0/ft1248_1bit_testbench.v create mode 100755 IPLIB/FT1248_streamio_v1_0/ft1248_streamio_v1_0.v create mode 100755 IPLIB/axi_stream_io_v1_0/axi_stream_io_v1_0.v create mode 100755 IPLIB/axi_stream_io_v1_0/axi_stream_io_v1_0_axi_s.v diff --git a/Cortex-M0/soclabs_demo/software/cmsis/Device/ARM/CMSDK_CM0/Include/CMSDK_CM0.h b/Cortex-M0/soclabs_demo/software/cmsis/Device/ARM/CMSDK_CM0/Include/CMSDK_CM0.h index f12a200..6744488 100644 --- a/Cortex-M0/soclabs_demo/software/cmsis/Device/ARM/CMSDK_CM0/Include/CMSDK_CM0.h +++ b/Cortex-M0/soclabs_demo/software/cmsis/Device/ARM/CMSDK_CM0/Include/CMSDK_CM0.h @@ -1,3 +1,14 @@ +//----------------------------------------------------------------------------- +// enhanced top-level example Cortex-M0 controller +// A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license. +// +// Contributors +// +// David Flynn (d.w.flynn@soton.ac.uk) +// +// Copyright © 2021-2, SoC Labs (www.soclabs.org) +//----------------------------------------------------------------------------- + /**************************************************************************//** * @file CMSDK_CM0.h * @brief CMSIS Cortex-M0 Core Peripheral Access Layer Header File for @@ -1257,7 +1268,7 @@ __IO uint32_t MODECTRL; #define CMSDK_DUALTIMER_2_BASE (CMSDK_DUALTIMER_BASE + 0x20UL) #define CMSDK_UART0_BASE (CMSDK_APB_BASE + 0x4000UL) #define CMSDK_UART1_BASE (CMSDK_APB_BASE + 0x5000UL) -#define CMSDK_UART2_BASE (CMSDK_APB_BASE + 0x6000UL) +#define CMSDK_UART2_BASE (CMSDK_APB_BASE + 0xE000UL) //0x6000UL) #define CMSDK_WATCHDOG_BASE (CMSDK_APB_BASE + 0x8000UL) #define CMSDK_PL230_BASE (CMSDK_APB_BASE + 0xF000UL) diff --git a/Cortex-M0/soclabs_demo/software/common/bootloader/bootloader.c b/Cortex-M0/soclabs_demo/software/common/bootloader/bootloader.c index 33838c9..12b2a64 100644 --- a/Cortex-M0/soclabs_demo/software/common/bootloader/bootloader.c +++ b/Cortex-M0/soclabs_demo/software/common/bootloader/bootloader.c @@ -119,7 +119,7 @@ int main (void) // UART init UartStdOutInit(); - UartPuts("\nGTRI-soclabs: ARM Cortex-M0 SDK\n"); // CMSDK boot loader\n"); + UartPuts("\nSOCLABS: ARM Cortex-M0 SDK\n"); // CMSDK boot loader\n"); UartPuts(" - load flash\n\n"); FlashLoader(); return 0; diff --git a/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/rtl_sim/adp.cmd b/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/rtl_sim/adp.cmd new file mode 100644 index 0000000..e46cc52 --- /dev/null +++ b/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/rtl_sim/adp.cmd @@ -0,0 +1,15 @@ +A +A 0 +R +R +A +A +A +a 20000200 +z 4000 +A +C 201 + + A +X +! diff --git a/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/bootrom.v b/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/bootrom.v index a640fee..12e24a8 100644 --- a/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/bootrom.v +++ b/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/bootrom.v @@ -5,7 +5,7 @@ // Contributors // // David Flynn (d.w.flynn@soton.ac.uk) -// Date: 220107 +// Date: 2203311024 // Copyright (c) 2021-2, SoC Labs (www.soclabs.org) //------------------------------------------------------------------------------------ module bootrom ( @@ -17,9 +17,9 @@ reg [9:2] addr_r; always @(posedge CLK) if (EN) addr_r <= ADDR; always @(addr_r) case(addr_r[9:2]) 8'h00 : RDATA <= 32'h20000368; // 0x0000 - 8'h01 : RDATA <= 32'h010002e1; // 0x0004 - 8'h02 : RDATA <= 32'h010002e9; // 0x0008 - 8'h03 : RDATA <= 32'h010002eb; // 0x000c + 8'h01 : RDATA <= 32'h010002dd; // 0x0004 + 8'h02 : RDATA <= 32'h010002e5; // 0x0008 + 8'h03 : RDATA <= 32'h010002e7; // 0x000c 8'h04 : RDATA <= 32'h00000000; // 0x0010 8'h05 : RDATA <= 32'h00000000; // 0x0014 8'h06 : RDATA <= 32'h00000000; // 0x0018 @@ -27,43 +27,43 @@ always @(addr_r) case(addr_r[9:2]) 8'h08 : RDATA <= 32'h00000000; // 0x0020 8'h09 : RDATA <= 32'h00000000; // 0x0024 8'h0a : RDATA <= 32'h00000000; // 0x0028 - 8'h0b : RDATA <= 32'h010002ed; // 0x002c + 8'h0b : RDATA <= 32'h010002e9; // 0x002c 8'h0c : RDATA <= 32'h00000000; // 0x0030 8'h0d : RDATA <= 32'h00000000; // 0x0034 - 8'h0e : RDATA <= 32'h010002ef; // 0x0038 - 8'h0f : RDATA <= 32'h010002f1; // 0x003c - 8'h10 : RDATA <= 32'h010002f3; // 0x0040 - 8'h11 : RDATA <= 32'h010002f3; // 0x0044 - 8'h12 : RDATA <= 32'h010002f3; // 0x0048 - 8'h13 : RDATA <= 32'h010002f3; // 0x004c - 8'h14 : RDATA <= 32'h010002f3; // 0x0050 - 8'h15 : RDATA <= 32'h010002f3; // 0x0054 - 8'h16 : RDATA <= 32'h010002f3; // 0x0058 - 8'h17 : RDATA <= 32'h010002f3; // 0x005c - 8'h18 : RDATA <= 32'h010002f3; // 0x0060 - 8'h19 : RDATA <= 32'h010002f3; // 0x0064 - 8'h1a : RDATA <= 32'h010002f3; // 0x0068 + 8'h0e : RDATA <= 32'h010002eb; // 0x0038 + 8'h0f : RDATA <= 32'h010002ed; // 0x003c + 8'h10 : RDATA <= 32'h010002ef; // 0x0040 + 8'h11 : RDATA <= 32'h010002ef; // 0x0044 + 8'h12 : RDATA <= 32'h010002ef; // 0x0048 + 8'h13 : RDATA <= 32'h010002ef; // 0x004c + 8'h14 : RDATA <= 32'h010002ef; // 0x0050 + 8'h15 : RDATA <= 32'h010002ef; // 0x0054 + 8'h16 : RDATA <= 32'h010002ef; // 0x0058 + 8'h17 : RDATA <= 32'h010002ef; // 0x005c + 8'h18 : RDATA <= 32'h010002ef; // 0x0060 + 8'h19 : RDATA <= 32'h010002ef; // 0x0064 + 8'h1a : RDATA <= 32'h010002ef; // 0x0068 8'h1b : RDATA <= 32'h00000000; // 0x006c - 8'h1c : RDATA <= 32'h010002f3; // 0x0070 - 8'h1d : RDATA <= 32'h010002f3; // 0x0074 - 8'h1e : RDATA <= 32'h010002f3; // 0x0078 - 8'h1f : RDATA <= 32'h010002f3; // 0x007c - 8'h20 : RDATA <= 32'h010002f3; // 0x0080 - 8'h21 : RDATA <= 32'h010002f3; // 0x0084 - 8'h22 : RDATA <= 32'h010002f3; // 0x0088 - 8'h23 : RDATA <= 32'h010002f3; // 0x008c - 8'h24 : RDATA <= 32'h010002f3; // 0x0090 - 8'h25 : RDATA <= 32'h010002f3; // 0x0094 - 8'h26 : RDATA <= 32'h010002f3; // 0x0098 - 8'h27 : RDATA <= 32'h010002f3; // 0x009c - 8'h28 : RDATA <= 32'h010002f3; // 0x00a0 - 8'h29 : RDATA <= 32'h010002f3; // 0x00a4 - 8'h2a : RDATA <= 32'h010002f3; // 0x00a8 - 8'h2b : RDATA <= 32'h010002f3; // 0x00ac - 8'h2c : RDATA <= 32'h010002f3; // 0x00b0 - 8'h2d : RDATA <= 32'h010002f3; // 0x00b4 - 8'h2e : RDATA <= 32'h010002f3; // 0x00b8 - 8'h2f : RDATA <= 32'h010002f3; // 0x00bc + 8'h1c : RDATA <= 32'h010002ef; // 0x0070 + 8'h1d : RDATA <= 32'h010002ef; // 0x0074 + 8'h1e : RDATA <= 32'h010002ef; // 0x0078 + 8'h1f : RDATA <= 32'h010002ef; // 0x007c + 8'h20 : RDATA <= 32'h010002ef; // 0x0080 + 8'h21 : RDATA <= 32'h010002ef; // 0x0084 + 8'h22 : RDATA <= 32'h010002ef; // 0x0088 + 8'h23 : RDATA <= 32'h010002ef; // 0x008c + 8'h24 : RDATA <= 32'h010002ef; // 0x0090 + 8'h25 : RDATA <= 32'h010002ef; // 0x0094 + 8'h26 : RDATA <= 32'h010002ef; // 0x0098 + 8'h27 : RDATA <= 32'h010002ef; // 0x009c + 8'h28 : RDATA <= 32'h010002ef; // 0x00a0 + 8'h29 : RDATA <= 32'h010002ef; // 0x00a4 + 8'h2a : RDATA <= 32'h010002ef; // 0x00a8 + 8'h2b : RDATA <= 32'h010002ef; // 0x00ac + 8'h2c : RDATA <= 32'h010002ef; // 0x00b0 + 8'h2d : RDATA <= 32'h010002ef; // 0x00b4 + 8'h2e : RDATA <= 32'h010002ef; // 0x00b8 + 8'h2f : RDATA <= 32'h010002ef; // 0x00bc 8'h30 : RDATA <= 32'hf802f000; // 0x00c0 8'h31 : RDATA <= 32'hf83ef000; // 0x00c4 8'h32 : RDATA <= 32'hc830a00c; // 0x00c8 @@ -79,8 +79,8 @@ always @(addr_r) case(addr_r[9:2]) 8'h3c : RDATA <= 32'h1afbd000; // 0x00f0 8'h3d : RDATA <= 32'h46ab46a2; // 0x00f4 8'h3e : RDATA <= 32'h47184333; // 0x00f8 - 8'h3f : RDATA <= 32'h00000288; // 0x00fc - 8'h40 : RDATA <= 32'h000002a8; // 0x0100 + 8'h3f : RDATA <= 32'h00000284; // 0x00fc + 8'h40 : RDATA <= 32'h000002a4; // 0x0100 8'h41 : RDATA <= 32'hd3023a10; // 0x0104 8'h42 : RDATA <= 32'hc178c878; // 0x0108 8'h43 : RDATA <= 32'h0752d8fa; // 0x010c @@ -97,14 +97,14 @@ always @(addr_r) case(addr_r[9:2]) 8'h4e : RDATA <= 32'h4770600b; // 0x0138 8'h4f : RDATA <= 32'hbd1fb51f; // 0x013c 8'h50 : RDATA <= 32'hbd10b510; // 0x0140 - 8'h51 : RDATA <= 32'hf8ebf000; // 0x0144 + 8'h51 : RDATA <= 32'hf8e9f000; // 0x0144 8'h52 : RDATA <= 32'hf7ff4611; // 0x0148 8'h53 : RDATA <= 32'hf000fff7; // 0x014c 8'h54 : RDATA <= 32'hf000f84a; // 0x0150 - 8'h55 : RDATA <= 32'hb403f903; // 0x0154 + 8'h55 : RDATA <= 32'hb403f901; // 0x0154 8'h56 : RDATA <= 32'hfff2f7ff; // 0x0158 8'h57 : RDATA <= 32'hf000bc03; // 0x015c - 8'h58 : RDATA <= 32'h0000f909; // 0x0160 + 8'h58 : RDATA <= 32'h0000f907; // 0x0160 8'h59 : RDATA <= 32'h68012000; // 0x0164 8'h5a : RDATA <= 32'h6841468d; // 0x0168 8'h5b : RDATA <= 32'h00004708; // 0x016c @@ -147,7 +147,7 @@ always @(addr_r) case(addr_r[9:2]) 8'h80 : RDATA <= 32'h07c96841; // 0x0200 8'h81 : RDATA <= 32'h6002d1fc; // 0x0204 8'h82 : RDATA <= 32'h2a001c5b; // 0x0208 - 8'h83 : RDATA <= 32'ha32ad1f5; // 0x020c + 8'h83 : RDATA <= 32'ha329d1f5; // 0x020c 8'h84 : RDATA <= 32'h2a00781a; // 0x0210 8'h85 : RDATA <= 32'h6841d006; // 0x0214 8'h86 : RDATA <= 32'hd1fc07c9; // 0x0218 @@ -169,7 +169,7 @@ always @(addr_r) case(addr_r[9:2]) 8'h96 : RDATA <= 32'h07c96841; // 0x0258 8'h97 : RDATA <= 32'h6002d1fc; // 0x025c 8'h98 : RDATA <= 32'h0000e7fe; // 0x0260 - 8'h99 : RDATA <= 32'h40006000; // 0x0264 + 8'h99 : RDATA <= 32'h4000e000; // 0x0264 8'h9a : RDATA <= 32'h40011000; // 0x0268 8'h9b : RDATA <= 32'h4001f000; // 0x026c 8'h9c : RDATA <= 32'h7245202d; // 0x0270 @@ -181,75 +181,75 @@ always @(addr_r) case(addr_r[9:2]) 8'ha2 : RDATA <= 32'h6c632079; // 0x0288 8'ha3 : RDATA <= 32'h0a726165; // 0x028c 8'ha4 : RDATA <= 32'h00000000; // 0x0290 - 8'ha5 : RDATA <= 32'h5254470a; // 0x0294 - 8'ha6 : RDATA <= 32'h6f732d49; // 0x0298 - 8'ha7 : RDATA <= 32'h62616c63; // 0x029c - 8'ha8 : RDATA <= 32'h41203a73; // 0x02a0 - 8'ha9 : RDATA <= 32'h43204d52; // 0x02a4 - 8'haa : RDATA <= 32'h6574726f; // 0x02a8 - 8'hab : RDATA <= 32'h304d2d78; // 0x02ac - 8'hac : RDATA <= 32'h4b445320; // 0x02b0 - 8'had : RDATA <= 32'h0000000a; // 0x02b4 - 8'hae : RDATA <= 32'h6c202d20; // 0x02b8 - 8'haf : RDATA <= 32'h2064616f; // 0x02bc - 8'hb0 : RDATA <= 32'h73616c66; // 0x02c0 - 8'hb1 : RDATA <= 32'h000a0a68; // 0x02c4 - 8'hb2 : RDATA <= 32'h48034904; // 0x02c8 - 8'hb3 : RDATA <= 32'h47706008; // 0x02cc - 8'hb4 : RDATA <= 32'h48014902; // 0x02d0 - 8'hb5 : RDATA <= 32'h47706008; // 0x02d4 - 8'hb6 : RDATA <= 32'h05f5e100; // 0x02d8 - 8'hb7 : RDATA <= 32'h20000000; // 0x02dc - 8'hb8 : RDATA <= 32'h47804807; // 0x02e0 - 8'hb9 : RDATA <= 32'h47004807; // 0x02e4 + 8'ha5 : RDATA <= 32'h434f530a; // 0x0294 + 8'ha6 : RDATA <= 32'h5342414c; // 0x0298 + 8'ha7 : RDATA <= 32'h5241203a; // 0x029c + 8'ha8 : RDATA <= 32'h6f43204d; // 0x02a0 + 8'ha9 : RDATA <= 32'h78657472; // 0x02a4 + 8'haa : RDATA <= 32'h20304d2d; // 0x02a8 + 8'hab : RDATA <= 32'h0a4b4453; // 0x02ac + 8'hac : RDATA <= 32'h00000000; // 0x02b0 + 8'had : RDATA <= 32'h6c202d20; // 0x02b4 + 8'hae : RDATA <= 32'h2064616f; // 0x02b8 + 8'haf : RDATA <= 32'h73616c66; // 0x02bc + 8'hb0 : RDATA <= 32'h000a0a68; // 0x02c0 + 8'hb1 : RDATA <= 32'h48034904; // 0x02c4 + 8'hb2 : RDATA <= 32'h47706008; // 0x02c8 + 8'hb3 : RDATA <= 32'h48014902; // 0x02cc + 8'hb4 : RDATA <= 32'h47706008; // 0x02d0 + 8'hb5 : RDATA <= 32'h05f5e100; // 0x02d4 + 8'hb6 : RDATA <= 32'h20000000; // 0x02d8 + 8'hb7 : RDATA <= 32'h47804807; // 0x02dc + 8'hb8 : RDATA <= 32'h47004807; // 0x02e0 + 8'hb9 : RDATA <= 32'he7fee7fe; // 0x02e4 8'hba : RDATA <= 32'he7fee7fe; // 0x02e8 8'hbb : RDATA <= 32'he7fee7fe; // 0x02ec - 8'hbc : RDATA <= 32'he7fee7fe; // 0x02f0 - 8'hbd : RDATA <= 32'h49054804; // 0x02f4 - 8'hbe : RDATA <= 32'h4b064a05; // 0x02f8 - 8'hbf : RDATA <= 32'h00004770; // 0x02fc - 8'hc0 : RDATA <= 32'h010002d1; // 0x0300 - 8'hc1 : RDATA <= 32'h010000c1; // 0x0304 - 8'hc2 : RDATA <= 32'h20000068; // 0x0308 - 8'hc3 : RDATA <= 32'h20000368; // 0x030c + 8'hbc : RDATA <= 32'h49054804; // 0x02f0 + 8'hbd : RDATA <= 32'h4b064a05; // 0x02f4 + 8'hbe : RDATA <= 32'h00004770; // 0x02f8 + 8'hbf : RDATA <= 32'h010002cd; // 0x02fc + 8'hc0 : RDATA <= 32'h010000c1; // 0x0300 + 8'hc1 : RDATA <= 32'h20000068; // 0x0304 + 8'hc2 : RDATA <= 32'h20000368; // 0x0308 + 8'hc3 : RDATA <= 32'h20000168; // 0x030c 8'hc4 : RDATA <= 32'h20000168; // 0x0310 - 8'hc5 : RDATA <= 32'h20000168; // 0x0314 - 8'hc6 : RDATA <= 32'h47704770; // 0x0318 - 8'hc7 : RDATA <= 32'h46754770; // 0x031c - 8'hc8 : RDATA <= 32'hf824f000; // 0x0320 - 8'hc9 : RDATA <= 32'h000546ae; // 0x0324 - 8'hca : RDATA <= 32'h46534669; // 0x0328 - 8'hcb : RDATA <= 32'h00c008c0; // 0x032c - 8'hcc : RDATA <= 32'hb0184685; // 0x0330 - 8'hcd : RDATA <= 32'hf7ffb520; // 0x0334 - 8'hce : RDATA <= 32'hbc60ffdd; // 0x0338 - 8'hcf : RDATA <= 32'h08492700; // 0x033c - 8'hd0 : RDATA <= 32'h260046b6; // 0x0340 + 8'hc5 : RDATA <= 32'h47704770; // 0x0314 + 8'hc6 : RDATA <= 32'h46754770; // 0x0318 + 8'hc7 : RDATA <= 32'hf824f000; // 0x031c + 8'hc8 : RDATA <= 32'h000546ae; // 0x0320 + 8'hc9 : RDATA <= 32'h46534669; // 0x0324 + 8'hca : RDATA <= 32'h00c008c0; // 0x0328 + 8'hcb : RDATA <= 32'hb0184685; // 0x032c + 8'hcc : RDATA <= 32'hf7ffb520; // 0x0330 + 8'hcd : RDATA <= 32'hbc60ffdd; // 0x0334 + 8'hce : RDATA <= 32'h08492700; // 0x0338 + 8'hcf : RDATA <= 32'h260046b6; // 0x033c + 8'hd0 : RDATA <= 32'hc5c0c5c0; // 0x0340 8'hd1 : RDATA <= 32'hc5c0c5c0; // 0x0344 8'hd2 : RDATA <= 32'hc5c0c5c0; // 0x0348 8'hd3 : RDATA <= 32'hc5c0c5c0; // 0x034c - 8'hd4 : RDATA <= 32'hc5c0c5c0; // 0x0350 - 8'hd5 : RDATA <= 32'h00493d40; // 0x0354 - 8'hd6 : RDATA <= 32'h4770468d; // 0x0358 - 8'hd7 : RDATA <= 32'h4604b510; // 0x035c - 8'hd8 : RDATA <= 32'h46c046c0; // 0x0360 - 8'hd9 : RDATA <= 32'hf7ff4620; // 0x0364 - 8'hda : RDATA <= 32'hbd10fef6; // 0x0368 - 8'hdb : RDATA <= 32'h47704800; // 0x036c - 8'hdc : RDATA <= 32'h20000004; // 0x0370 - 8'hdd : RDATA <= 32'h20184901; // 0x0374 - 8'hde : RDATA <= 32'he7febeab; // 0x0378 - 8'hdf : RDATA <= 32'h00020026; // 0x037c - 8'he0 : RDATA <= 32'h00004770; // 0x0380 - 8'he1 : RDATA <= 32'h010003a4; // 0x0384 - 8'he2 : RDATA <= 32'h20000000; // 0x0388 - 8'he3 : RDATA <= 32'h00000004; // 0x038c - 8'he4 : RDATA <= 32'h01000104; // 0x0390 - 8'he5 : RDATA <= 32'h010003a8; // 0x0394 - 8'he6 : RDATA <= 32'h20000004; // 0x0398 - 8'he7 : RDATA <= 32'h00000364; // 0x039c - 8'he8 : RDATA <= 32'h01000120; // 0x03a0 - 8'he9 : RDATA <= 32'h05f5e100; // 0x03a4 + 8'hd4 : RDATA <= 32'h00493d40; // 0x0350 + 8'hd5 : RDATA <= 32'h4770468d; // 0x0354 + 8'hd6 : RDATA <= 32'h4604b510; // 0x0358 + 8'hd7 : RDATA <= 32'h46c046c0; // 0x035c + 8'hd8 : RDATA <= 32'hf7ff4620; // 0x0360 + 8'hd9 : RDATA <= 32'hbd10fef8; // 0x0364 + 8'hda : RDATA <= 32'h47704800; // 0x0368 + 8'hdb : RDATA <= 32'h20000004; // 0x036c + 8'hdc : RDATA <= 32'h20184901; // 0x0370 + 8'hdd : RDATA <= 32'he7febeab; // 0x0374 + 8'hde : RDATA <= 32'h00020026; // 0x0378 + 8'hdf : RDATA <= 32'h00004770; // 0x037c + 8'he0 : RDATA <= 32'h010003a0; // 0x0380 + 8'he1 : RDATA <= 32'h20000000; // 0x0384 + 8'he2 : RDATA <= 32'h00000004; // 0x0388 + 8'he3 : RDATA <= 32'h01000104; // 0x038c + 8'he4 : RDATA <= 32'h010003a4; // 0x0390 + 8'he5 : RDATA <= 32'h20000004; // 0x0394 + 8'he6 : RDATA <= 32'h00000364; // 0x0398 + 8'he7 : RDATA <= 32'h01000120; // 0x039c + 8'he8 : RDATA <= 32'h05f5e100; // 0x03a0 + 8'he9 : RDATA <= 32'h00000000; // 0x03a4 8'hea : RDATA <= 32'h00000000; // 0x03a8 8'heb : RDATA <= 32'h00000000; // 0x03ac 8'hec : RDATA <= 32'h00000000; // 0x03b0 diff --git a/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/cmsdk_apb_uart_streamio.v b/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/cmsdk_apb_uart_streamio.v new file mode 100644 index 0000000..12ddbd5 --- /dev/null +++ b/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/cmsdk_apb_uart_streamio.v @@ -0,0 +1,1157 @@ +//----------------------------------------------------------------------------- +// customised top-level example Cortex-M0 controller +// A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license. +// +// Contributors +// +// David Flynn (d.w.flynn@soton.ac.uk) +// +// Copyright © 2021-2, SoC Labs (www.soclabs.org) +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// The confidential and proprietary information contained in this file may +// only be used by a person authorised under and to the extent permitted +// by a subsisting licensing agreement from Arm Limited or its affiliates. +// +// (C) COPYRIGHT 2010-2011 Arm Limited or its affiliates. +// ALL RIGHTS RESERVED +// +// This entire notice must be reproduced on all copies of this file +// and copies of this file may only be made by a person if such person is +// permitted to do so under the terms of a subsisting license agreement +// from Arm Limited or its affiliates. +// +// SVN Information +// +// Checked In : $Date: 2017-10-10 15:55:38 +0100 (Tue, 10 Oct 2017) $ +// +// Revision : $Revision: 371321 $ +// +// Release Information : Cortex-M System Design Kit-r1p1-00rel0 +// +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// Abstract : Simple APB UART +//----------------------------------------------------------------------------- +//------------------------------------- +// Programmer's model +// 0x00 R RXD[7:0] Received Data +// W TXD[7:0] Transmit data +// 0x04 RW STAT[3:0] +// [3] RX buffer overrun (write 1 to clear) +// [2] TX buffer overrun (write 1 to clear) +// [1] RX buffer full (Read only) +// [0] TX buffer full (Read only) +// 0x08 RW CTRL[3:0] TxIntEn, RxIntEn, TxEn, RxEn +// [6] High speed test mode Enable +// [5] RX overrun interrupt enable +// [4] TX overrun interrupt enable +// [3] RX Interrupt Enable +// [2] TX Interrupt Enable +// [1] RX Enable +// [0] TX Enable +// 0x0C R/Wc intr_status/INTCLEAR +// [3] RX overrun interrupt +// [2] TX overrun interrupt +// [1] RX interrupt +// [0] TX interrupt +// 0x10 RW BAUDDIV[19:0] Baud divider +// (minimum value is 16) +// 0x3E0 - 0x3FC ID registers +//------------------------------------- + +module cmsdk_apb_uart_streamio ( +// -------------------------------------------------------------------------- +// Port Definitions +// -------------------------------------------------------------------------- + input wire PCLK, // Clock + input wire PCLKG, // Gated Clock + input wire PRESETn, // Reset + + input wire PSEL, // Device select + input wire [11:2] PADDR, // Address + input wire PENABLE, // Transfer control + input wire PWRITE, // Write control + input wire [31:0] PWDATA, // Write data + + input wire [3:0] ECOREVNUM,// Engineering-change-order revision bits + + output wire [31:0] PRDATA, // Read data + output wire PREADY, // Device ready + output wire PSLVERR, // Device error response + + input wire RXD, // Serial input + output wire TXD, // Transmit data output + output wire TXEN, // Transmit enabled + output wire BAUDTICK, // Baud rate (x16) Tick + + output wire TX_VALID_o, + output wire [7:0] TX_DATA8_o, + input wire TX_READY_i, + + input wire RX_VALID_i, + input wire [7:0] RX_DATA8_i, + output wire RX_READY_o, + + output wire TXINT, // Transmit Interrupt + output wire RXINT, // Receive Interrupt + output wire TXOVRINT, // Transmit overrun Interrupt + output wire RXOVRINT, // Receive overrun Interrupt + output wire UARTINT); // Combined interrupt + +// Local ID parameters, APB UART part number is 0x821 +localparam ARM_CMSDK_APB_UART_PID4 = 8'h04; +localparam ARM_CMSDK_APB_UART_PID5 = 8'h00; +localparam ARM_CMSDK_APB_UART_PID6 = 8'h00; +localparam ARM_CMSDK_APB_UART_PID7 = 8'h00; +localparam ARM_CMSDK_APB_UART_PID0 = 8'h21; +localparam ARM_CMSDK_APB_UART_PID1 = 8'hB8; +localparam ARM_CMSDK_APB_UART_PID2 = 8'h1B; +localparam ARM_CMSDK_APB_UART_PID3 = 4'h0; +localparam ARM_CMSDK_APB_UART_CID0 = 8'h0D; +localparam ARM_CMSDK_APB_UART_CID1 = 8'hF0; +localparam ARM_CMSDK_APB_UART_CID2 = 8'h05; +localparam ARM_CMSDK_APB_UART_CID3 = 8'hB1; + + // -------------------------------------------------------------------------- + // Internal wires + // -------------------------------------------------------------------------- +// Signals for read/write controls +wire read_enable; +wire write_enable; +wire write_enable00; // Write enable for data register +wire write_enable04; // Write enable for Status register +wire write_enable08; // Write enable for control register +wire write_enable0c; // Write enable for interrupt status register +wire write_enable10; // Write enable for Baud rate divider +reg [7:0] read_mux_byte0; // Read data multiplexer for lower 8-bit +reg [7:0] read_mux_byte0_reg; // Register read data for lower 8-bit +wire [31:0] read_mux_word; // Read data multiplexer for whole 32-bit +wire [3:0] pid3_value; // constant value for lower 4-bit in perpherial ID3 + +// Signals for Control registers +reg [6:0] reg_ctrl; // Control register +reg [7:0] reg_tx_buf; // Transmit data buffer +reg [7:0] reg_rx_buf; // Receive data buffer +reg [19:0] reg_baud_div; // Baud rate setting + +// Internal signals + // Baud rate divider +reg [15:0] reg_baud_cntr_i; // baud rate divider counter i (integer) +wire [15:0] nxt_baud_cntr_i; +reg [3:0] reg_baud_cntr_f; // baud rate divider counter f (fraction) +wire [3:0] nxt_baud_cntr_f; +wire [3:0] mapped_cntr_f; // remapped counter f value +reg reg_baud_tick; // Register baud rate tick (16 times of baud rate) +reg baud_updated; // baud rate value has bee updated from APB +wire reload_i; // baud rate divider counter i reload +wire reload_f; // baud rate divider counter f reload +wire baud_div_en; // enable baud rate counter + + // Status +wire [3:0] uart_status; // UART status +reg reg_rx_overrun; // Receive overrun status register +wire rx_overrun; // Receive overrun detection +reg reg_tx_overrun; // Transmit overrun status register +wire tx_overrun; // Transmit overrun detection +wire nxt_rx_overrun; // next state for reg_rx_overrun +wire nxt_tx_overrun; // next state for reg_tx_overrun + // Interrupts +reg reg_txintr; // Transmit interrupt register +reg reg_rxintr; // Receive interrupt register +wire tx_overflow_intr;// Transmit overrun/overflow interrupt +wire rx_overflow_intr;// Receive overrun/overflow interrupt +wire [3:0] intr_state; // UART interrupt status +wire [1:0] intr_stat_set; // Set TX/RX interrupt +wire [1:0] intr_stat_clear; // Clear TX/RX interrupt + + // transmit +reg [3:0] tx_state; // Transmit FSM state +reg [4:0] nxt_tx_state; +wire tx_state_update; +wire tx_state_inc; // Bit pulse +reg [3:0] tx_tick_cnt; // Transmit Tick counter +wire [4:0] nxt_tx_tick_cnt; +reg [7:0] tx_shift_buf; // Transmit shift register +wire [7:0] nxt_tx_shift_buf; // next state for tx_shift_buf +wire tx_buf_ctrl_shift; // shift control for tx_shift_buf +wire tx_buf_ctrl_load; // load control for tx_shift_buf +reg tx_buf_full; // TX Buffer full +reg reg_txd; // Tx Data +wire nxt_txd; // next state of reg_txd +wire update_reg_txd; // update reg_txd +wire tx_buf_clear; // Clear buffer full status when data is load into TX shift register + + // Receive data sync and filter +reg rxd_sync_1; // Double flip-flop syncrhoniser +reg rxd_sync_2; // Double flip-flop syncrhoniser +reg [2:0] rxd_lpf; // Averaging Low Pass Filter +wire [2:0] nxt_rxd_lpf; +wire rx_shift_in; // Shift Register Input + + // Receiver +reg [3:0] rx_state; // Receiver FSM state +reg [4:0] nxt_rx_state; +wire rx_state_update; +reg [3:0] rx_tick_cnt; // Receiver Tick counter +wire [4:0] nxt_rx_tick_cnt; +wire update_rx_tick_cnt; +wire rx_state_inc;// Bit pulse +reg [6:0] rx_shift_buf;// Receiver shift data register +wire [6:0] nxt_rx_shift_buf; +reg rx_buf_full; // Receive buffer full status +wire nxt_rx_buf_full; +wire rxbuf_sample; // Sample received data into receive data buffer +wire rx_data_read; // Receive data buffer read by APB interface +wire [7:0] nxt_rx_buf; + +// Start of main code +// Read and write control signals +assign read_enable = PSEL & (~PWRITE); // assert for whole APB read transfer +assign write_enable = PSEL & (~PENABLE) & PWRITE; // assert for 1st cycle of write transfer +assign write_enable00 = write_enable & (PADDR[11:2] == 10'h000); +assign write_enable04 = write_enable & (PADDR[11:2] == 10'h001); +assign write_enable08 = write_enable & (PADDR[11:2] == 10'h002); +assign write_enable0c = write_enable & (PADDR[11:2] == 10'h003); +assign write_enable10 = write_enable & (PADDR[11:2] == 10'h004); + +// Write operations + // Transmit data register + always @(posedge PCLKG or negedge PRESETn) + begin + if (~PRESETn) + reg_tx_buf <= {8{1'b0}}; + else if (write_enable00) + reg_tx_buf <= PWDATA[7:0]; + end + + assign TX_DATA8_o = reg_tx_buf[7:0]; + + // Status register overrun registers + assign nxt_rx_overrun = (reg_rx_overrun & (~((write_enable04|write_enable0c) & PWDATA[3]))) | rx_overrun; + assign nxt_tx_overrun = (reg_tx_overrun & (~((write_enable04|write_enable0c) & PWDATA[2]))) | tx_overrun; + + // RX OverRun status + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + reg_rx_overrun <= 1'b0; + else if (rx_overrun | write_enable04 | write_enable0c) + reg_rx_overrun <= nxt_rx_overrun; + end + + // TX OverRun status + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + reg_tx_overrun <= 1'b0; + else if (tx_overrun | write_enable04 | write_enable0c) + reg_tx_overrun <= nxt_tx_overrun; + end + + // Control register + always @(posedge PCLKG or negedge PRESETn) + begin + if (~PRESETn) + reg_ctrl <= {7{1'b0}}; + else if (write_enable08) + reg_ctrl <= PWDATA[6:0]; + end + + // Baud rate divider - integer + always @(posedge PCLKG or negedge PRESETn) + begin + if (~PRESETn) + reg_baud_div <= {20{1'b0}}; + else if (write_enable10) + reg_baud_div <= PWDATA[19:0]; + end + +// Read operation + assign uart_status = {reg_rx_overrun, reg_tx_overrun, rx_buf_full, tx_buf_full}; + + assign pid3_value = ARM_CMSDK_APB_UART_PID3; + + // First level of read mux + always @(PADDR or reg_rx_buf or uart_status or reg_ctrl or intr_state or reg_baud_div + or ECOREVNUM or pid3_value) + begin + if (PADDR[11:5] == 7'h00) begin + case (PADDR[4:2]) + 3'h0: read_mux_byte0 = reg_rx_buf; + 3'h1: read_mux_byte0 = {{4{1'b0}},uart_status}; + 3'h2: read_mux_byte0 = {{1{1'b0}},reg_ctrl}; + 3'h3: read_mux_byte0 = {{4{1'b0}},intr_state}; + 3'h4: read_mux_byte0 = reg_baud_div[7:0]; + 3'h5, 3'h6, 3'h7: read_mux_byte0 = {8{1'b0}}; //default read out value + default: read_mux_byte0 = {8{1'bx}};// x propogation + endcase + end + else if (PADDR[11:6] == 6'h3F) begin + case (PADDR[5:2]) + 4'h0, 4'h1,4'h2,4'h3: read_mux_byte0 = {8{1'b0}}; //default read out value + // ID register - constant values + 4'h4: read_mux_byte0 = ARM_CMSDK_APB_UART_PID4; // 0xFD0 : PID 4 + 4'h5: read_mux_byte0 = ARM_CMSDK_APB_UART_PID5; // 0xFD4 : PID 5 + 4'h6: read_mux_byte0 = ARM_CMSDK_APB_UART_PID6; // 0xFD8 : PID 6 + 4'h7: read_mux_byte0 = ARM_CMSDK_APB_UART_PID7; // 0xFDC : PID 7 + 4'h8: read_mux_byte0 = ARM_CMSDK_APB_UART_PID0; // 0xFE0 : PID 0 APB UART part number[7:0] + 4'h9: read_mux_byte0 = ARM_CMSDK_APB_UART_PID1; // 0xFE0 : PID 1 [7:4] jep106_id_3_0. [3:0] part number [11:8] + 4'hA: read_mux_byte0 = ARM_CMSDK_APB_UART_PID2; // 0xFE0 : PID 2 [7:4] revision, [3] jedec_used. [2:0] jep106_id_6_4 + 4'hB: read_mux_byte0 = {ECOREVNUM[3:0],pid3_value[3:0]}; + // 0xFE0 : PID 3 [7:4] ECO revision, [3:0] modification number + 4'hC: read_mux_byte0 = ARM_CMSDK_APB_UART_CID0; // 0xFF0 : CID 0 + 4'hD: read_mux_byte0 = ARM_CMSDK_APB_UART_CID1; // 0xFF4 : CID 1 PrimeCell class + 4'hE: read_mux_byte0 = ARM_CMSDK_APB_UART_CID2; // 0xFF8 : CID 2 + 4'hF: read_mux_byte0 = ARM_CMSDK_APB_UART_CID3; // 0xFFC : CID 3 + default : read_mux_byte0 = {8{1'bx}}; // x propogation + endcase + end + else begin + read_mux_byte0 = {8{1'b0}}; //default read out value + end + end + + + + // Register read data + always @(posedge PCLKG or negedge PRESETn) + begin + if (~PRESETn) + read_mux_byte0_reg <= {8{1'b0}}; + else if (read_enable) + read_mux_byte0_reg <= read_mux_byte0; + end + + // Second level of read mux + assign read_mux_word[ 7: 0] = read_mux_byte0_reg; + assign read_mux_word[19: 8] = (PADDR[11:2]==10'h004) ? reg_baud_div[19:8] : {12{1'b0}}; + assign read_mux_word[31:20] = {12{1'b0}}; + + + // Output read data to APB + assign PRDATA[31: 0] = (read_enable) ? read_mux_word : {32{1'b0}}; + assign PREADY = 1'b1; // Always ready + assign PSLVERR = 1'b0; // Always okay + +// -------------------------------------------- +// Baud rate generator + // Baud rate generator enable + assign baud_div_en = (reg_ctrl[1:0] != 2'b00); + assign mapped_cntr_f = {reg_baud_cntr_f[0],reg_baud_cntr_f[1], + reg_baud_cntr_f[2],reg_baud_cntr_f[3]}; + // Reload Integer divider + // when UART enabled and (reg_baud_cntr_f < reg_baud_div[3:0]) + // then count to 1, or + // when UART enabled then count to 0 + assign reload_i = (baud_div_en & + (((mapped_cntr_f >= reg_baud_div[3:0]) & + (reg_baud_cntr_i[15:1] == {15{1'b0}})) | + (reg_baud_cntr_i[15:0] == {16{1'b0}}))); + + // Next state for Baud rate divider + assign nxt_baud_cntr_i = (baud_updated | reload_i) ? reg_baud_div[19:4] : + (reg_baud_cntr_i - 16'h0001); + // Update at reload or decrement + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + reg_baud_cntr_i <= {16{1'b0}}; + else if (baud_updated | baud_div_en) + reg_baud_cntr_i <= nxt_baud_cntr_i; + end + + // Reload fraction divider + assign reload_f = baud_div_en & (reg_baud_cntr_f==4'h0) & + reload_i; + // Next state for fraction part of Baud rate divider + assign nxt_baud_cntr_f = + (reload_f|baud_updated) ? 4'hF : + (reg_baud_cntr_f - 4'h1); + + // Update at reload or decrement + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + reg_baud_cntr_f <= {4{1'b0}}; + else if (baud_updated | reload_f | reload_i) + reg_baud_cntr_f <= nxt_baud_cntr_f; + end + + // Generate control signal to update baud rate counters + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + baud_updated <= 1'b0; + else if (write_enable10 | baud_updated) + // Baud rate updated - to load new value to counters + baud_updated <= write_enable10; + end + + // Generate Tick signal for external logic + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + reg_baud_tick <= 1'b0; + else if (reload_i | reg_baud_tick) + reg_baud_tick <= reload_i; + end + + // Connect to external + assign BAUDTICK = reg_baud_tick; + +// -------------------------------------------- +// Transmit + + // Buffer full status + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + tx_buf_full <= 1'b0; + else if (write_enable00) // | tx_buf_clear) + tx_buf_full <= write_enable00; + else if (tx_buf_full & TX_READY_i) // AXI stream ack + tx_buf_full <= 0; + end + + assign TX_VALID_o = tx_buf_full; + + // Increment TickCounter + assign nxt_tx_tick_cnt = ((tx_state==4'h1) & reg_baud_tick) ? {5{1'b0}} : + tx_tick_cnt + {{3{1'b0}},reg_baud_tick}; + + // Registering TickCounter + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + tx_tick_cnt <= {4{1'b0}}; + else if (reg_baud_tick) + tx_tick_cnt <= nxt_tx_tick_cnt[3:0]; + end + + // Increment state (except Idle(0) and Wait for Tick(1)) + assign tx_state_inc = (((&tx_tick_cnt)|(tx_state==4'h1)) & reg_baud_tick)|reg_ctrl[6]; + // state increment every cycle of high speed test mode is enabled + // Clear buffer full status when data is load into shift register + assign tx_buf_clear = ((tx_state==4'h0) & tx_buf_full) | + ((tx_state==4'hB) & tx_buf_full & tx_state_inc); + + // tx_state machine + // 0 = Idle, 1 = Wait for Tick, + // 2 = Start bit, 3 = D0 .... 10 = D7 + // 11 = Stop bit + always @(tx_state or tx_buf_full or tx_state_inc or reg_ctrl) + begin + case (tx_state) + 0: begin + nxt_tx_state = (tx_buf_full & reg_ctrl[0]) ? 5'h01 : 5'h00; // New data is written to buffer + end + 1, // State 1 : Wait for next Tick + 2,3,4,5,6,7,8,9,10: begin // State 2-10: Start bit, D0 - D7 + nxt_tx_state = tx_state + {3'b000,tx_state_inc}; + end + 11: begin // Stop bit , goto next start bit or Idle + nxt_tx_state = (tx_state_inc) ? ( tx_buf_full ? 5'h02:5'h00) : {1'b0, tx_state}; + end + default: + nxt_tx_state = {5{1'bx}}; + endcase + end + + assign tx_state_update = tx_state_inc | ((tx_state==4'h0) & tx_buf_full & reg_ctrl[0]) | (tx_state>4'd11); + + // Registering outputs + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + tx_state <= {4{1'b0}}; + else if (tx_state_update) + tx_state <= nxt_tx_state[3:0]; + end + + // Load/shift TX register + assign tx_buf_ctrl_load = (((tx_state==4'h0) & tx_buf_full) | + ((tx_state==4'hB) & tx_buf_full & tx_state_inc)); + assign tx_buf_ctrl_shift = ((tx_state>4'h2) & tx_state_inc); + + assign nxt_tx_shift_buf = tx_buf_ctrl_load ? reg_tx_buf[7:0] : {1'b1,tx_shift_buf[7:1]}; + + // Registering TX shift register + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + tx_shift_buf <= {8{1'b0}}; + else if (tx_buf_ctrl_shift | tx_buf_ctrl_load) + tx_shift_buf <= nxt_tx_shift_buf; + end + + // Data output + assign nxt_txd = (tx_state==4'h2) ? 1'b0 : + (tx_state>4'h2) ? tx_shift_buf[0] : 1'b1; + + assign update_reg_txd = (nxt_txd != reg_txd); + + // Registering outputs + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + reg_txd <= 1'b1; + else if (update_reg_txd) + reg_txd <= nxt_txd; + end + + // Generate TX overrun error status + assign tx_overrun = tx_buf_full & (~tx_buf_clear) & write_enable00; + + // Connect to external + assign TXD = reg_txd; + assign TXEN = reg_ctrl[0]; + +// -------------------------------------------- +// Receive synchronizer and low pass filter + + // Doubling Flip-flop synxt_rx_tick_cntnchroniser + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + begin + rxd_sync_1 <= 1'b1; + rxd_sync_2 <= 1'b1; + end + else if (reg_ctrl[1]) // Turn off synchronizer if receive is not enabled + begin + rxd_sync_1 <= RXD; + rxd_sync_2 <= rxd_sync_1; + end + end + + // Averaging low pass filter + assign nxt_rxd_lpf = {rxd_lpf[1:0], rxd_sync_2}; + // Registering stage for low pass filter + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + rxd_lpf <= 3'b111; + else if (reg_baud_tick) + rxd_lpf <= nxt_rxd_lpf; + end + + // Averaging values + assign rx_shift_in = (rxd_lpf[1] & rxd_lpf[0]) | + (rxd_lpf[1] & rxd_lpf[2]) | + (rxd_lpf[0] & rxd_lpf[2]); + +// -------------------------------------------- +// Receive + + // Increment TickCounter + assign nxt_rx_tick_cnt = ((rx_state==4'h0) & (~rx_shift_in)) ? 5'h08 : + rx_tick_cnt + {{3{1'b0}},reg_baud_tick}; + + assign update_rx_tick_cnt = ((rx_state==4'h0) & (~rx_shift_in)) | reg_baud_tick; + + // Registering other register + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + rx_tick_cnt <= {4{1'b0}}; + else if (update_rx_tick_cnt) + rx_tick_cnt <= nxt_rx_tick_cnt[3:0]; + end + + // Increment state + assign rx_state_inc = ((&rx_tick_cnt) & reg_baud_tick); + // Buffer full status + assign nxt_rx_buf_full = rxbuf_sample | (rx_buf_full & (~rx_data_read)); + + // Sample shift register when D7 is sampled +/// assign rxbuf_sample = ((rx_state==4'h9) & rx_state_inc); + assign rxbuf_sample = RX_VALID_i & !rx_buf_full; + + // Reading receive buffer (Set at 1st cycle of APB transfer + // because read mux is registered before output) + assign rx_data_read = (PSEL & (~PENABLE) & (PADDR[11:2]==10'h000) & (~PWRITE)); + // Generate RX overrun error status + assign rx_overrun = rx_buf_full & rxbuf_sample & (~rx_data_read); + + // rx_state machine + // 0 = Idle, 1 = Start of Start bit detected + // 2 = Sample Start bit, 3 = D0 .... 10 = D7 + // 11 = Stop bit + // 11, 12, 13, 14, 15: illegal/unused states + always @(rx_state or rx_shift_in or rx_state_inc or reg_ctrl) + begin + case (rx_state) + 0: begin + nxt_rx_state = ((~rx_shift_in) & reg_ctrl[1]) ? 5'h01 : 5'h00; // Wait for Start bit + end + 1, // State 1 : Wait for middle of start bit + 2,3,4,5,6,7,8,9: begin // State 2-9: D0 - D7 + nxt_rx_state = rx_state + {3'b000,rx_state_inc}; + end + 10: begin // Stop bit , goto back to Idle + nxt_rx_state = (rx_state_inc) ? 5'h00 : 5'h0A; + end + default: + nxt_rx_state = {5{1'bx}}; + endcase + end + + assign rx_state_update = rx_state_inc | ((~rx_shift_in) & reg_ctrl[1]); + + // Registering rx_state + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + rx_state <= {4{1'b0}}; + else if (rx_state_update) + rx_state <= nxt_rx_state[3:0]; + end + + // Buffer full status + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + rx_buf_full <= 1'b0; + else if (rxbuf_sample | rx_data_read) + rx_buf_full <= nxt_rx_buf_full; + end + + // Sample receive buffer +/// assign nxt_rx_buf = {rx_shift_in, rx_shift_buf}; + assign nxt_rx_buf = RX_DATA8_i[7:0]; + + // Registering receive data buffer + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + reg_rx_buf <= {8{1'b0}}; + else if (rxbuf_sample) + reg_rx_buf <= nxt_rx_buf; + end + + // Shift register + assign nxt_rx_shift_buf= {rx_shift_in, rx_shift_buf[6:1]}; + // Registering shift buffer + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + rx_shift_buf <= {7{1'b0}}; + else if (rx_state_inc) + rx_shift_buf <= nxt_rx_shift_buf; + end + + + +// -------------------------------------------- +// Interrupts + // Set by event + assign intr_stat_set[1] = reg_ctrl[3] & rxbuf_sample; // A new receive data is sampled + assign intr_stat_set[0] = reg_ctrl[2] & reg_ctrl[0] & tx_buf_full & tx_buf_clear; + // Falling edge of buffer full + // Clear by write to IntClear register + assign intr_stat_clear[1:0] = {2{write_enable0c}} & PWDATA[1:0]; + + // Registering outputs + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + reg_txintr <= 1'b0; + else if (intr_stat_set[0] | intr_stat_clear[0]) + reg_txintr <= intr_stat_set[0]; + end + + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + reg_rxintr <= 1'b0; + else if (intr_stat_set[1] | intr_stat_clear[1]) + reg_rxintr <= intr_stat_set[1]; + end + + assign rx_overflow_intr = reg_rx_overrun & reg_ctrl[5]; + assign tx_overflow_intr = reg_tx_overrun & reg_ctrl[4]; + + // Interrupt status for read back + assign intr_state = {rx_overflow_intr, tx_overflow_intr, reg_rxintr, reg_txintr}; + + // Connect to external + assign TXINT = reg_txintr; + assign RXINT = reg_rxintr; + assign TXOVRINT = tx_overflow_intr; + assign RXOVRINT = rx_overflow_intr; + assign UARTINT = reg_txintr | reg_rxintr | tx_overflow_intr | rx_overflow_intr; + + +`ifdef ARM_APB_ASSERT_ON + // ------------------------------------------------------------ + // Assertions + // ------------------------------------------------------------ +`include "std_ovl_defines.h" + + // Prepare signals for OVL checking + reg [15:0] ovl_last_reg_baud_cntr_i; + reg [3:0] ovl_last_reg_baud_cntr_f; + reg ovl_last_baud_div_en; + reg ovl_last_baud_updated; + always @(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + begin + ovl_last_reg_baud_cntr_i <= {16{1'b0}}; + ovl_last_reg_baud_cntr_f <= {4{1'b0}}; + ovl_last_baud_div_en <= 1'b0; + ovl_last_baud_updated <= 1'b0; + end + else + begin + ovl_last_reg_baud_cntr_i <= reg_baud_cntr_i; + ovl_last_reg_baud_cntr_f <= reg_baud_cntr_f; + ovl_last_baud_div_en <= baud_div_en; + ovl_last_baud_updated <= baud_updated; + end + end + + reg ovl_reg_hs_test_mode_triggered; // Indicate if HighSpeed testmode has been activated + wire ovl_nxt_hs_test_mode_triggered; + reg [7:0] ovl_reg_tx_tick_count; // For measuring width of TX state + wire [7:0] ovl_nxt_tx_tick_count; + reg [7:0] ovl_reg_rx_tick_count; // For measuring width of RX state + wire [7:0] ovl_nxt_rx_tick_count; + reg [3:0] ovl_reg_last_tx_state; // last state + reg [3:0] ovl_reg_last_rx_state; + reg [6:0] ovl_last_reg_ctrl; + + // Clear test mode indicator each time state is changed, set to 1 if high speed test mode is + // enabled + assign ovl_nxt_hs_test_mode_triggered = + (tx_state!=ovl_reg_last_tx_state) ? reg_ctrl[6]: (reg_ctrl[6] | ovl_reg_hs_test_mode_triggered); + + // Counter clear at each state change, increasement at each reg_baud_tick + assign ovl_nxt_tx_tick_count = (tx_state!=ovl_reg_last_tx_state) ? (8'h00) : + (ovl_reg_tx_tick_count + {{7{1'b0}}, reg_baud_tick}); + + // Counter clear at each state change, increasement at each reg_baud_tick + assign ovl_nxt_rx_tick_count = (rx_state!=ovl_reg_last_rx_state) ? (8'h00) : + (ovl_reg_rx_tick_count + {{7{1'b0}}, reg_baud_tick}); + + always@(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + begin + ovl_reg_hs_test_mode_triggered <= 1'b0; + ovl_reg_last_tx_state <= 4'h0; + ovl_reg_last_rx_state <= 4'h0; + ovl_reg_tx_tick_count <= 8'h00; + ovl_reg_rx_tick_count <= 8'h00; + ovl_last_reg_ctrl <= 7'h00; + end + else + begin + ovl_reg_hs_test_mode_triggered <= ovl_nxt_hs_test_mode_triggered; + ovl_reg_last_tx_state <= tx_state; + ovl_reg_last_rx_state <= rx_state; + ovl_reg_tx_tick_count <= ovl_nxt_tx_tick_count; + ovl_reg_rx_tick_count <= ovl_nxt_rx_tick_count; + ovl_last_reg_ctrl <= reg_ctrl; + end + end + + // Signals for checking clearing of interrupts + reg ovl_last_txint; + reg ovl_last_rxint; + reg ovl_last_psel; + reg ovl_last_penable; + reg ovl_last_pwrite; + reg [31:0] ovl_last_pwdata; + reg [11:2] ovl_last_paddr; + reg ovl_last_rx_buf_full; + reg ovl_last_tx_shift_buf_0; + + + always@(posedge PCLK or negedge PRESETn) + begin + if (~PRESETn) + begin + ovl_last_txint <= 1'b0; + ovl_last_rxint <= 1'b0; + ovl_last_psel <= 1'b0; + ovl_last_penable <= 1'b0; + ovl_last_pwrite <= 1'b0; + ovl_last_paddr <= {10{1'b0}}; + ovl_last_pwdata <= {32{1'b0}}; + ovl_last_rx_buf_full <= 1'b0; + ovl_last_tx_shift_buf_0 <= 1'b0; + end + else + begin + ovl_last_txint <= TXINT; + ovl_last_rxint <= RXINT; + ovl_last_psel <= PSEL; + ovl_last_penable <= PENABLE; + ovl_last_pwrite <= PWRITE; + ovl_last_paddr <= PADDR; + ovl_last_pwdata <= PWDATA; + ovl_last_rx_buf_full <= rx_buf_full; + ovl_last_tx_shift_buf_0 <= tx_shift_buf[0]; + end + end + + // Ensure rx_state must not be 11, 12, 13, 14, 15 + assert_never + #(`OVL_ERROR,`OVL_ASSERT, + "rx_state in illegal state") + u_ovl_rx_state_illegal + (.clk(PCLK), .reset_n(PRESETn), + .test_expr((rx_state==4'hB)|(rx_state==4'hC)|(rx_state==4'hD)| + (rx_state==4'hE)|(rx_state==4'hF))); + + // Ensure tx_state must not be 12, 13, 14, 15 + assert_never + #(`OVL_ERROR,`OVL_ASSERT, + "tx_state in illegal state") + u_ovl_tx_state_illegal + (.clk(PCLK), .reset_n(PRESETn), + .test_expr((tx_state==4'hC)|(tx_state==4'hD)| + (tx_state==4'hE)|(tx_state==4'hF))); + + // Ensure reg_baud_cntr_i change only if UART is enabled + // or if write to baud rate divider + assert_implication + #(`OVL_ERROR,`OVL_ASSERT, + "Unexpected baud rate divider change") + u_ovl_reg_baud_cntr_i_change + (.clk(PCLK), .reset_n(PRESETn), + .antecedent_expr(ovl_last_reg_baud_cntr_i!=reg_baud_cntr_i), + .consequent_expr(ovl_last_baud_div_en | ovl_last_baud_updated ) + ); + + // Ensure reg_baud_div[19:4] >= reg_baud_cntr_i unless reg_baud_div just been programmed + assert_implication + #(`OVL_ERROR,`OVL_ASSERT, + "Unexpected baud rate divided change") + u_ovl_reg_baud_cntr_i_range + (.clk(PCLK), .reset_n(PRESETn), + .antecedent_expr(reg_baud_cntr_i>reg_baud_div[19:4]), + .consequent_expr(baud_updated) + ); + + // Ensure reg_baud_cntr_f change only if UART is enabled + // or if write to baud rate divider + assert_implication + #(`OVL_ERROR,`OVL_ASSERT, + "Unexpected baud rate divider change") + u_ovl_reg_baud_cntr_f_change + (.clk(PCLK), .reset_n(PRESETn), + .antecedent_expr(ovl_last_reg_baud_cntr_f!=reg_baud_cntr_f), + .consequent_expr(ovl_last_baud_div_en | ovl_last_baud_updated ) + ); + + // Ensure tx_buf_full is set to 1 after write to TX buffer (PADDR[11:2]==0) + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "tx_buf_full should be asserted after write to TX buffer") + u_ovl_tx_buf_full + (.clk(PCLK), .reset_n(PRESETn), + .start_event (PSEL & (~PENABLE) & PWRITE & (PADDR[11:2] == 10'h000)), + .test_expr (tx_buf_full) + ); + + // If last tx_state=0 (idle) or 1 (wait for tick), TXD = 1. + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "TXD should be 1 when idle or just before data transmission") + u_ovl_txd_state_0_1 + (.clk(PCLK), .reset_n(PRESETn), + .start_event ((tx_state==4'd0)|(tx_state==4'd1)), + .test_expr (TXD==1'b1) + ); + + // If last tx_state=2 (start bit), TXD = 0. + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "TXD should be 0 when output start bit") + u_ovl_txd_state_2 + (.clk(PCLK), .reset_n(PRESETn), + .start_event (tx_state==4'd2), + .test_expr (TXD==1'b0) + ); + + // If last tx_state=3-10 (D0 to D7), TXD = anything (tx_shift_buf[0]). + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "TXD should be same as first bit of shift register during transfer") + u_ovl_txd_state_3_to_10 + (.clk(PCLK), .reset_n(PRESETn), + .start_event ((tx_state>4'd2) & (tx_state<4'd11)), + .test_expr (TXD==ovl_last_tx_shift_buf_0) + ); + + // If last tx_state=11 (stop bit), TXD = 1. + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "TXD should be 1 when output stop bit") + u_ovl_txd_state_11 + (.clk(PCLK), .reset_n(PRESETn), + .start_event (tx_state==4'd11), + .test_expr (TXD==1'b1) + ); + + // Duration of tx_state in 2 to 11 must have 16 reg_baud_tick + // (unless high speed test mode has been active) + assert_implication + #(`OVL_ERROR,`OVL_ASSERT, + "Duration of tx_state when in state 2 to state 11 should have 16 ticks") + u_ovl_width_of_tx_state + (.clk(PCLK), .reset_n(PRESETn), + .antecedent_expr((tx_state!=ovl_reg_last_tx_state) & // at state change + (ovl_reg_last_tx_state>4'd1)&(ovl_reg_last_tx_state<4'd12) & // from state 2 to 11 + (ovl_reg_hs_test_mode_triggered==1'b0)), // high speed test mode not triggered + .consequent_expr((ovl_reg_tx_tick_count==8'd15) | (ovl_reg_tx_tick_count==8'd16)) + // count from 0 to 15 (16 ticks) + ); + + + // In high speed test mode, tx_state must change if it is in range of 2 to 11 + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "Duration of tx_state should be 1 cycle if high speed test mode is enabled") + u_ovl_width_of_tx_state_in_high_speed_test_mode + (.clk(PCLK), .reset_n(PRESETn), + .start_event((tx_state>4'd1)&(tx_state<4'd12) & reg_ctrl[6]), + .test_expr (tx_state != ovl_reg_last_tx_state) + ); + + // Duration of rx_state in 1 must have 8 reg_baud_tick + assert_implication + #(`OVL_ERROR,`OVL_ASSERT, + "Duration of rx_state when state 1 should have 8 ticks") + u_ovl_width_of_rx_state_1 + (.clk(PCLK), .reset_n(PRESETn), + .antecedent_expr((rx_state!=ovl_reg_last_rx_state) & // at state change + (ovl_reg_last_rx_state==4'd1)), // last state was state 1 + .consequent_expr((ovl_reg_rx_tick_count==8'd7)|(ovl_reg_rx_tick_count==8'd8)) + // count from 0 to 7 (8 ticks) + ); + + // Duration of rx_state in 2 to 10 must have 16 reg_baud_tick + assert_implication + #(`OVL_ERROR,`OVL_ASSERT, + "Duration of rx_state when in state 2 to state 10 should have 16 ticks") + u_ovl_width_of_rx_state_data + (.clk(PCLK), .reset_n(PRESETn), + .antecedent_expr((rx_state!=ovl_reg_last_rx_state) & // at state change + (ovl_reg_last_rx_state>4'd1)&(ovl_reg_last_rx_state<4'd11)), // from state 2 to 9 + .consequent_expr((ovl_reg_rx_tick_count==8'd15)|(ovl_reg_rx_tick_count==8'd16)) + // count from 0 to 15 (16 ticks) + ); + + // UARTINT must be 0 if TXINT, RXINT, TXOVRINT and RXOVRINT are all 0 + assert_implication + #(`OVL_ERROR,`OVL_ASSERT, + "UARTINT must be 0 if TXINT, RXINT, TXOVRINT and RXOVRINT are all 0") + u_ovl_uartint_mismatch + (.clk(PCLK), .reset_n(PRESETn), + .antecedent_expr((TXINT | RXINT | TXOVRINT | RXOVRINT) == 1'b0), // No interrupt + .consequent_expr(UARTINT==1'b0) // Combined interrupt = 0 + ); + + // TXINT should be asserted when TX interrupt enabled and transmit buffer is available + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "TXINT should be triggered when enabled") + u_ovl_txint_enable + (.clk(PCLK ), .reset_n (PRESETn), + .start_event (reg_ctrl[0] & reg_ctrl[2] & tx_buf_full & tx_buf_clear), + .test_expr (TXINT == 1'b1) + ); + + // There should be no rising edge of TXINT if transmit is disabled or transmit interrupt is disabled + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "TXINT should not be triggered when disabled") + u_ovl_txint_disable + (.clk(PCLK ), .reset_n (PRESETn), + .start_event (((reg_ctrl[0]==1'b0) | (reg_ctrl[2]==1'b0)) & (TXINT == 1'b0)), + .test_expr (TXINT == 1'b0) + ); + + // if TXINT falling edge, there must has been a write to INTCLEAR register with bit[0]=1 + assert_implication + #(`OVL_ERROR,`OVL_ASSERT, + "When there is a falling edge of TXINT, there must has been a write to INTCLEAR") + u_ovl_txint_clear + (.clk(PCLK), .reset_n(PRESETn), + .antecedent_expr(ovl_last_txint & (~TXINT)), // Falling edge of TXINT + .consequent_expr(ovl_last_psel & ovl_last_pwrite & + (ovl_last_paddr==10'h003) & (ovl_last_pwdata[0]) ) // There must has been a write to INTCLEAR + ); + + // RXINT should be asserted when RX interrupt enabled and a new data is received + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "RXINT should be triggered when enabled") + u_ovl_rxint_enable + (.clk(PCLK ), .reset_n (PRESETn), + .start_event (reg_ctrl[3] & (rx_state==9) & (nxt_rx_state==10)), + .test_expr (RXINT == 1'b1) + ); + + // There should be no rising edge of RXINT if receive interrupt is disabled + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "RXINT should not be triggered when disabled") + u_ovl_rxint_disable + (.clk(PCLK ), .reset_n (PRESETn), + .start_event ((reg_ctrl[3]==1'b0) & (RXINT == 1'b0)), + .test_expr (RXINT == 1'b0) + ); + + // if RXINT falling edge, there must has been a write to INTCLEAR register with bit[1]=1 + assert_implication + #(`OVL_ERROR,`OVL_ASSERT, + "When there is a falling edge of RXINT, there must has been a write to INTCLEAR") + u_ovl_rxint_clear + (.clk(PCLK), .reset_n(PRESETn), + .antecedent_expr(ovl_last_rxint & (~RXINT)), // Falling edge of TXINT + .consequent_expr(ovl_last_psel & ovl_last_pwrite & + (ovl_last_paddr==10'h003) & (ovl_last_pwdata[1]) ) // There must has been a write to INTCLEAR + ); + + // rx_buf_full should rise if rx_state change from 9 to 10 + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "rx_buf_full should be asserted when a new character is received") + u_ovl_rx_buf_full + (.clk(PCLK ), .reset_n (PRESETn), + .start_event ((rx_state==9) & (nxt_rx_state==10)), + .test_expr (rx_buf_full == 1'b1) + ); + + // if rx_buf_full falling edge, there must has been a read to the receive buffer + assert_implication + #(`OVL_ERROR,`OVL_ASSERT, + "When there is a falling edge of RXINT, there must has been a read to receive buffer") + u_ovl_rx_buf_full_clear + (.clk(PCLK), .reset_n(PRESETn), + .antecedent_expr((~rx_buf_full) & ovl_last_rx_buf_full), // Falling edge of rx_buf_full + .consequent_expr(ovl_last_psel & (~ovl_last_pwrite) & + (ovl_last_paddr==10'h000) ) // There must has been a read to rx data + ); + + // TXOVRINT must be 0 if reg_ctrl[4]=0 + assert_implication + #(`OVL_ERROR,`OVL_ASSERT, + "When there is a falling edge of RXINT, there must has been a write to INTCLEAR") + u_ovl_txovrint_disable + (.clk(PCLK), .reset_n(PRESETn), + .antecedent_expr(~reg_ctrl[4]), + .consequent_expr(~TXOVRINT) + ); + + // RXOVRINT must be 0 if reg_ctrl[5]=0 + assert_implication + #(`OVL_ERROR,`OVL_ASSERT, + "When there is a falling edge of RXINT, there must has been a write to INTCLEAR") + u_ovl_rxovrint_disable + (.clk(PCLK), .reset_n(PRESETn), + .antecedent_expr(~reg_ctrl[5]), + .consequent_expr(~RXOVRINT) + ); + + // if a write take place to TX data buffer and tx_buf_full was 1, reg_tx_overrun will be set + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "tx buffer overrun should be asserted when a new character is write to buffer and buffer is already full") + u_ovl_tx_buffer_overrun + (.clk(PCLK ), .reset_n (PRESETn), + .start_event (write_enable00 & tx_buf_full & (~tx_buf_clear)), + .test_expr (reg_tx_overrun == 1'b1) + ); + + // if rx_buf_full is high and rx_state change from 9 to 10, reg_rx_overrun will be set + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "rx buffer overrun should be asserted when a new character is received and rx buffer is already full") + u_ovl_rx_buffer_overrun + (.clk(PCLK ), .reset_n (PRESETn), + .start_event (rx_buf_full & (~rx_data_read) & (rx_state==9) & (nxt_rx_state==10)), + .test_expr (reg_rx_overrun == 1'b1) + ); + + // if write to INTCLEAR with bit[2]=1, reg_tx_overrun will be cleared, + // Cannot have new overrun at the same time because the APB can only do onething at a time + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "tx buffer overrun should be clear when write to INTCLEAR") + u_ovl_tx_buffer_overrun_clear_a + (.clk(PCLK ), .reset_n (PRESETn), + .start_event (write_enable0c & (PWDATA[2])), + .test_expr (reg_tx_overrun==1'b0) + ); + + // if write to STATUS with bit[2]=1, reg_tx_overrun will be cleared, + // Cannot have new overrun at the same time because the APB can only do onething at a time + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "tx buffer overrun should be clear when write to INTCLEAR") + u_ovl_tx_buffer_overrun_clear_b + (.clk(PCLK ), .reset_n (PRESETn), + .start_event (write_enable04 & (PWDATA[2])), + .test_expr (reg_tx_overrun==1'b0) + ); + + // if write to INTCLEAR with bit[3]=1, reg_rx_overrun will be cleared, unless a new overrun take place + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "rx buffer overrun should be clear when write to INTCLEAR, unless new overrun") + u_ovl_rx_buffer_overrun_clear_a + (.clk(PCLK ), .reset_n (PRESETn), + .start_event (write_enable0c & (PWDATA[3]) & (~(rx_buf_full & (rx_state==9) & (nxt_rx_state==10)))), + .test_expr (reg_rx_overrun==1'b0) + ); + + // If rx buffer is not full, it cannot have new overrun + assert_next + #(`OVL_ERROR, 1,1,0, `OVL_ASSERT, + "rx buffer overrun should be clear when write to INTCLEAR, unless new overrun") + u_ovl_rx_buffer_overrun_when_empty + (.clk(PCLK ), .reset_n (PRESETn), + .start_event ((~rx_buf_full) & (reg_rx_overrun==1'b0)), + .test_expr (reg_rx_overrun==1'b0) + ); + + + // Reading of reg_baud_div (worth checking due to two stage read mux) + assert_next + #(`OVL_ERROR, 1, 1, 0, `OVL_ASSERT, + "Reading of baud rate divider value") + u_ovl_read_baud_rate_divide_cfg + (.clk(PCLK ), .reset_n (PRESETn), + .start_event (PSEL & (~PENABLE) & (~PWRITE) & (PADDR[11:2]==10'h004)), + .test_expr (PRDATA=={{12{1'b0}}, reg_baud_div}) + ); + + // Recommended Baud Rate divider value is at least 16 + assert_never + #(`OVL_ERROR,`OVL_ASSERT, + "UART enabled with baud rate less than 16") + u_ovl_baud_rate_divider_illegal + (.clk(PCLK), .reset_n(PRESETn), + .test_expr(((reg_ctrl[0]) & (reg_ctrl[6]==1'b0) & (reg_baud_div[19:4]=={16{1'b0}}) ) | + ((reg_ctrl[1]) & (reg_baud_div[19:4]=={16{1'b0}}) ) ) + ); + + // Test mode never changes from hi-speed to normal speed unless TX is idle + assert_never + #(`OVL_ERROR,`OVL_ASSERT, + "High speed test mode has been changed when TX was not idle") + u_ovl_change_speed_tx_illegal + (.clk(PCLK), .reset_n(PRESETn), + .test_expr((tx_state != 4'd00) & (reg_ctrl[6] != ovl_last_reg_ctrl[6])) + ); + +`endif + +endmodule diff --git a/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/cmsdk_ft1248x1_adpio.v b/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/cmsdk_ft1248x1_adpio.v new file mode 100644 index 0000000..89ecfe6 --- /dev/null +++ b/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/cmsdk_ft1248x1_adpio.v @@ -0,0 +1,157 @@ +//----------------------------------------------------------------------------- +// customised example Cortex-M0 controller UART with file logging +// A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license. +// +// Contributors +// +// David Flynn (d.w.flynn@soton.ac.uk) +// +// Copyright © 2022, SoC Labs (www.soclabs.org) +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Abstract : FT1248 1-bit data off-chip interface (emulate FT232H device) +// and allows cmsdk_uart_capture testbench models to log ADP ip, op streams +//----------------------------------------------------------------------------- + + +module cmsdk_ft1248x1_adpio + #(parameter ADPFILENAME = "adp.cmd", + parameter VERBOSE = 0) + ( + input wire ft_clk_i, // SCLK + input wire ft_ssn_i, // SS_N + output wire ft_miso_o, // MISO + inout wire ft_miosio_io, // MIOSIO tristate output when enabled + + output wire FTDI_CLK2UART_o, // Clock (baud rate) + output wire FTDI_OP2UART_o, // Received data to UART capture + output wire FTDI_IP2UART_o // Transmitted data to UART capture + ); + + + //---------------------------------------------- + //-- File I/O + //---------------------------------------------- + + + integer fdcmd; // channel descriptor for cmd file input + integer ch; +`define EOF -1 + + reg ft_rxreq; + wire ft_rxack; + reg [7:0] ft_adpbyte; + + initial + begin + ft_rxreq <= 0; + $timeformat(-9, 0, " ns", 14); + fdcmd= $fopen(ADPFILENAME,"r"); + if (fdcmd == 0) + $write("** FT1248x1 : no command file **\n"); + else begin + ch = $fgetc(fdcmd); + while (ch != `EOF) begin + ft_adpbyte <= (ch & 8'hff); + ft_rxreq <= 1'b1; + while (ft_ssn_i == 1'b0) + @(posedge ft_ssn_i); + @(posedge ft_rxack); + ft_rxreq <=0; + @(negedge ft_rxack); + ch = $fgetc(fdcmd); + end + end + $fclose(fdcmd); + ft_rxreq <= 0; + end + + +//---------------------------------------------- +//-- State Machine +//---------------------------------------------- + +wire ft_miosio_i; +wire ft_miosio_o; +wire ft_miosio_z; + +// tri-state pad control for MIOSIO +assign ft_miosio_io = (ft_miosio_z) ? 1'bz : ft_miosio_o; +// add notinal delay on inout to ensure last "half-bit" on FT1248TXD is sampled before tri-stated +assign #1 ft_miosio_i = ft_miosio_io; + +reg [4:0] ft_state; // 17-state for bit-serial +wire [5:0] ft_nextstate = ft_state + 5'b00001; + +always @(posedge ft_clk_i or posedge ft_ssn_i) + if (ft_ssn_i) + ft_state <= 5'b11111; + else // loop if multi-data +// ft_state <= (ft_state == 5'b01111) ? 5'b01000 : ft_nextstate; + ft_state <= ft_nextstate; + +// 16: bus turnaround (or bit[5]) +// 0 for CMD3 +// 3 for CMD2 +// 5 for CMD1 +// 6 for CMD0 +// 7 for cmd turnaround +// 8 for data bit0 +// 9 for data bit1 +// 10 for data bit2 +// 11 for data bit3 +// 12 for data bit4 +// 13 for data bit5 +// 14 for data bit6 +// 15 for data bit7 + +// ft_miso_o reflects RXE when deselected +assign ft_miso_o = (ft_ssn_i) ? !ft_rxreq : (ft_state == 5'b00111); + +// capture CMD on falling edge of clock (mid-data) +// - valid sample ready after 7th edge (ready RX or TX data phase functionality) +reg [7:0] ft_cmd; +always @(negedge ft_clk_i or posedge ft_ssn_i) + if (ft_ssn_i) + ft_cmd <= 8'b00000001; + else // shift in data + ft_cmd <= (!ft_state[3] & !ft_nextstate[3]) ? {ft_cmd[6:0],ft_miosio_i} : ft_cmd; + +wire ft_cmd_valid = ft_cmd[7]; +wire ft_cmd_rxd = ft_cmd[7] & !ft_cmd[6] & !ft_cmd[3] & !ft_cmd[1] & ft_cmd[0]; +wire ft_cmd_txd = ft_cmd[7] & !ft_cmd[6] & !ft_cmd[3] & !ft_cmd[1] & !ft_cmd[0]; + +// tristate enable for miosio (deselected status or serialized data for read command) +wire ft_miosio_e = ft_ssn_i | (ft_cmd_rxd & !ft_state[4] & ft_state[3]); +assign ft_miosio_z = !ft_miosio_e; + +// serial data formatted with start bit for UART capture (on rising uart-clock) +assign FTDI_CLK2UART_o = !ft_clk_i; +// suitable for CMSDK UART capture IO +// inject a start bit low else mark high +assign FTDI_OP2UART_o = (ft_cmd_txd & (ft_state[4:3]) == 2'b01) ? ft_miosio_i : !(ft_cmd_txd & (ft_state == 5'b00111)); +assign FTDI_IP2UART_o = (ft_cmd_rxd & (ft_state[4:3]) == 2'b01) ? ft_miosio_io : !(ft_cmd_rxd & (ft_state == 5'b00111)); + +// capture RXD on falling edge of clock +reg [8:0] ft_rxd; +always @(negedge ft_clk_i or posedge ft_ssn_i) + if (ft_ssn_i) + ft_rxd <= 9'b111111111; + else if (ft_cmd_txd & !(ft_miosio_i & (&ft_rxd[8:0]))) //only on valid start-bit + ft_rxd <= {ft_miosio_i, ft_rxd[8:1]}; + +// shift TXD on rising edge of clock +reg [8:0] ft_txd; +always @(posedge ft_clk_i or posedge ft_ssn_i) + if (ft_ssn_i) + ft_txd <= {1'b1,ft_adpbyte}; + else if (ft_rxreq & ft_cmd_rxd & (ft_state[4:3] == 2'b01)) //valid TX shift + ft_txd <= {1'b0,ft_txd[8:1]}; + +assign ft_rxack = (ft_cmd_rxd & (ft_state==5'b01111)); + +// ft_miso_o reflects TXF when deselected (never full for simulation output) +assign ft_miosio_o = (ft_ssn_i) ? 1'b0 : ft_txd[0]; + +endmodule diff --git a/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/cmsdk_mcu.v b/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/cmsdk_mcu.v index 1aeb28f..e2fc1c4 100644 --- a/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/cmsdk_mcu.v +++ b/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/cmsdk_mcu.v @@ -6,7 +6,7 @@ // // David Flynn (d.w.flynn@soton.ac.uk) // -// Copyright © 2021, SoC Labs (www.soclabs.org) +// Copyright © 2021-2, SoC Labs (www.soclabs.org) //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- @@ -207,14 +207,18 @@ module cmsdk_mcu #( wire dmac_done; wire dmac_err; - wire dmac_psel; - wire dmac_pready; wire exp_penable; wire exp_pwrite; wire [11:0] exp_paddr; wire [31:0] exp_pwdata; - wire dmac_pslverr; - wire [31:0] dmac_prdata; + wire exp14_psel; + wire exp14_pready; + wire exp14_pslverr; + wire [31:0] exp14_prdata; + wire exp15_psel; + wire exp15_pready; + wire exp15_pslverr; + wire [31:0] exp15_prdata; // Flash memory AHB signals wire flash_hsel; @@ -259,6 +263,14 @@ module cmsdk_mcu #( wire [15:0] p1_outen; wire [15:0] p1_altfunc; + wire ft_clk_o; + wire ft_ssn_o; + wire ft_miso_i; + wire ft_miosio_o; + wire ft_miosio_e; + wire ft_miosio_z; + wire ft_miosio_i; + localparam BASEADDR_GPIO0 = 32'h4001_0000; localparam BASEADDR_GPIO1 = 32'h4001_1000; localparam BASEADDR_SYSROMTABLE = 32'hF000_0000; @@ -501,6 +513,7 @@ module cmsdk_mcu #( // DMA Controller // ------------------------------- +/* // DMA interface not used in this example system wire [DMA_CHANNEL_NUM-1:0] dma230_tie0; // tie off signal. @@ -537,16 +550,16 @@ module cmsdk_mcu #( .hwdata (dmac_hwdata), // APB Slave Interface .pclken (PCLKEN), - .psel (dmac_psel), + .psel (exp15_psel), .pen (exp_penable), .pwrite (exp_pwrite), .paddr (exp_paddr[11:0]), .pwdata (exp_pwdata[31:0]), - .prdata (dmac_prdata) + .prdata (exp15_prdata) ); - assign dmac_pready = 1'b1; - assign dmac_pslverr = 1'b0; + assign exp15_pready = 1'b1; + assign exp15_pslverr = 1'b0; assign dmac_done = |dma230_done_ch; // OR all the DMA done together end else begin : gen_no_pl230_udma @@ -562,13 +575,130 @@ module cmsdk_mcu #( assign dmac_done = 1'b0; assign dmac_err = 1'b0; - assign dmac_pready = 1'b1; - assign dmac_pslverr = 1'b0; - assign dmac_prdata = 32'h00000000; + assign exp15_pready = 1'b1; + assign exp15_pslverr = 1'b0; + assign exp15_prdata = 32'h00000000; assign dma230_done_ch = {DMA_CHANNEL_NUM{1'b0}}; end endgenerate +*/ + wire comio_tx_ready; + wire [7:0] comio_tx_data8; + wire comio_tx_valid; + + wire comio_rx_ready; + wire [7:0] comio_rx_data8; + wire comio_rx_valid; + + wire stdio_tx_ready; + wire [7:0] stdio_tx_data8; + wire stdio_tx_valid; + + wire stdio_rx_ready; + wire [7:0] stdio_rx_data8; + wire stdio_rx_valid; + + wire [7:0] adp_gpo8; + wire [7:0] adp_gpi8; + + assign adp_gpi8 = adp_gpo8; + + // DMA controller present + ADPcontrol_v1_0 u_ADP ( + // Clock and Reset + .ahb_hclk (HCLKSYS), + .ahb_hresetn (HRESETn), + // DMA Control + .com_rx_tready (comio_rx_ready), + .com_rx_tdata (comio_rx_data8), + .com_rx_tvalid (comio_rx_valid), + .com_tx_tready (comio_tx_ready), + .com_tx_tdata (comio_tx_data8), + .com_tx_tvalid (comio_tx_valid), + .stdio_rx_tready (stdio_rx_ready), + .stdio_rx_tdata (stdio_rx_data8), + .stdio_rx_tvalid (stdio_rx_valid), + .stdio_tx_tready (stdio_tx_ready), + .stdio_tx_tdata (stdio_tx_data8), + .stdio_tx_tvalid (stdio_tx_valid), + .gpo8 (adp_gpo8), + .gpi8 (adp_gpi8), + // AHB-Lite Master Interface + .ahb_hready (dmac_hready), + .ahb_hresp (dmac_hresp), + .ahb_hrdata (dmac_hrdata), + .ahb_htrans (dmac_htrans), + .ahb_hwrite (dmac_hwrite), + .ahb_haddr (dmac_haddr), + .ahb_hsize (dmac_hsize), + .ahb_hburst (dmac_hburst), + .ahb_hmastlock (dmac_hmastlock), + .ahb_hprot (dmac_hprot), + .ahb_hwdata (dmac_hwdata) + ); + + +// cmsdk_apb_uart_streamio u_apb_uart_com ( + cmsdk_apb_uart u_apb_uart_com ( + .PCLK (PCLK), // Peripheral clock + .PCLKG (PCLKG), // Gated PCLK for bus + .PRESETn (PRESETn), // Reset + + .PSEL (exp14_psel), // APB interface inputs + .PADDR (exp_paddr[11:2]), + .PENABLE (exp_penable), + .PWRITE (exp_pwrite), + .PWDATA (exp_pwdata), + .PRDATA (exp14_prdata), // APB interface outputs + .PREADY (exp14_pready), + .PSLVERR (exp14_pslverr), + + .ECOREVNUM (4'h0),// Engineering-change-order revision bits + + .RXD (uart2_rxd), // Receive data + + .TXD (uart2_txd), // Transmit data + .TXEN (uart2_txen), // Transmit Enabled + + .BAUDTICK ( ), // Baud rate x16 tick output (for testing) + + .TXINT ( ), // Transmit Interrupt + .RXINT ( ), // Receive Interrupt + .TXOVRINT ( ), // Transmit Overrun Interrupt + .RXOVRINT ( ), // Receive Overrun Interrupt + .UARTINT ( ) // Combined Interrupt + ); + + wire [7:0] ft_clkdiv = 8'd32; + + ft1248_streamio_v1_0 # + (.FT1248_WIDTH (1), + .FT1248_CLKON(0) ) + u_ftdio_com ( + .clk (HCLKSYS), + .resetn (HRESETn), + .ft_clkdiv (ft_clkdiv ), + .ft_clk_o (ft_clk_o ), + .ft_ssn_o (ft_ssn_o ), + .ft_miso_i (ft_miso_i ), + .ft_miosio_o (ft_miosio_o ), + .ft_miosio_e (ft_miosio_e ), + .ft_miosio_z (ft_miosio_z ), + .ft_miosio_i (ft_miosio_i ), + .rxd_tready (comio_tx_ready), + .rxd_tdata (comio_tx_data8), + .rxd_tvalid (comio_tx_valid), + .rxd_tlast (1'b0), + .txd_tready (comio_rx_ready), + .txd_tdata (comio_rx_data8), + .txd_tvalid (comio_rx_valid), + .txd_tlast ( ) + ); + + assign ft_miso_i = 1'b1; + assign ft_miosio_i = 1'b1; + //--------------------------------------------------- // System design for example Cortex-M0/Cortex-M0+ MCU //--------------------------------------------------- @@ -679,8 +809,8 @@ module cmsdk_mcu #( .uart1_txd (uart1_txd), .uart1_txen (uart1_txen), .uart2_rxd (uart2_rxd), - .uart2_txd (uart2_txd), - .uart2_txen (uart2_txen), + .uart2_txd ( ), //uart2_txd), + .uart2_txen ( ), //uart2_txen), // Timer .timer0_extin (timer0_extin), @@ -719,16 +849,28 @@ module cmsdk_mcu #( .dmac_hprot (dmac_hprot), .dmac_hwdata (dmac_hwdata), // APB Slave Interface - .dmac_psel (dmac_psel), + .exp12_psel ( ), + .exp13_psel ( ), + .exp14_psel (exp14_psel), + .exp15_psel ( ), .exp_penable (exp_penable), .exp_pwrite (exp_pwrite), .exp_paddr (exp_paddr[11:0]), .exp_pwdata (exp_pwdata[31:0]), - .dmac_prdata (dmac_prdata), - .dmac_pready (1'b1), - .dmac_pslverr (1'b0), - - .DFTSE (1'b0) + .exp12_prdata (32'h00000000), + .exp12_pready (1'b1), + .exp12_pslverr (1'b0), + .exp13_prdata (32'h00000000), + .exp13_pready (1'b1), + .exp13_pslverr (1'b0), + .exp14_prdata (exp14_prdata), + .exp14_pready (exp14_pready), + .exp14_pslverr (exp14_pslverr), + .exp15_prdata (exp15_prdata), + .exp15_pready (1'b1), + .exp15_pslverr (1'b0), + + .DFTSE (1'b0) ); //---------------------------------------- @@ -775,8 +917,8 @@ cmsdk_ahb_rom //---------------------------------------- // Only use if BOOT_MEM_TYPE is not zero `ifdef SYNTHBOOTROM -//ahb_bootrom -ahb_bootrom__mangled +ahb_bootrom +//ahb_bootrom__mangled // #(.AW(10) ) // 1K bytes ROM u_ahb_bootloader ( .HCLK (HCLKSYS), diff --git a/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/cmsdk_mcu_chip.v b/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/cmsdk_mcu_chip.v index 7a840f7..7de3697 100644 --- a/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/cmsdk_mcu_chip.v +++ b/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/cmsdk_mcu_chip.v @@ -6,7 +6,7 @@ // // David Flynn (d.w.flynn@soton.ac.uk) // -// Copyright © 2021, SoC Labs (www.soclabs.org) +// Copyright © 2021-2, SoC Labs (www.soclabs.org) //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- @@ -143,7 +143,16 @@ module cmsdk_mcu_chip #( wire swdio_out_nen; wire swdclk_in; + wire ft_clk_o ; + wire ft_ssn_o ; + wire ft_miso_i; + wire ft_miosio_o; + wire ft_miosio_e; + wire ft_miosio_z; + wire ft_miosio_i; + wire ADPRESETREQ; + /* cmsdk_mcu_core #(.CLKGATE_PRESENT (CLKGATE_PRESENT), @@ -306,7 +315,7 @@ PAD_INOUT8MA_NOE uPAD_P0_03 ( .I (p0_in[03]), .NOE (p0_out_nen[03]) ); - + PAD_INOUT8MA_NOE uPAD_P0_04 ( .PAD (P0[04]), .O (p0_out[04]), @@ -392,7 +401,7 @@ PAD_INOUT8MA_NOE uPAD_P0_15 ( ); // GPI.I Port 1 x 16 - +/* PAD_INOUT8MA_NOE uPAD_P1_00 ( .PAD (P1[00]), .O (p1_out_mux[00]), @@ -420,6 +429,38 @@ PAD_INOUT8MA_NOE uPAD_P1_03 ( .I (p1_in[03]), .NOE (p1_out_nen_mux[03]) ); +*/ + +PAD_INOUT8MA_NOE uPAD_P1_00 ( + .PAD (P1[00]), + .O (1'b0), //p1_out[00]), + .I (ft_miso_i), //p1_in[00]), + .NOE (1'b1) //p1_out_nen[00]) + ); +assign p1_in[00] = ft_miso_i; + +PAD_INOUT8MA_NOE uPAD_P1_01 ( + .PAD (P1[01]), + .O (ft_clk_o ), //p1_out[01]), + .I (p1_in[01]), + .NOE (1'b0) //p1_out_nen[01]) + ); + +PAD_INOUT8MA_NOE uPAD_P1_02 ( + .PAD (P1[02]), + .O (ft_miosio_o), //p1_out[02]), + .I (ft_miosio_i), //p1_in[02]), + .NOE (ft_miosio_z) //p1_out_nen[02]) + ); +assign p1_in[02] = ft_miosio_i; + +PAD_INOUT8MA_NOE uPAD_P1_03 ( + .PAD (P1[03]), + .O (ft_ssn_o), + .I (p1_in[03]), + .NOE (1'b0) + ); + PAD_INOUT8MA_NOE uPAD_P1_04 ( .PAD (P1[04]), @@ -586,14 +627,18 @@ PAD_INOUT8MA_NOE uPAD_P1_15 ( wire dmac_done; wire dmac_err; - wire dmac_psel; - wire dmac_pready; wire exp_penable; wire exp_pwrite; wire [11:0] exp_paddr; wire [31:0] exp_pwdata; - wire dmac_pslverr; - wire [31:0] dmac_prdata; + wire exp15_psel; + wire exp15_pready; + wire exp15_pslverr; + wire [31:0] exp15_prdata; + wire exp14_psel; + wire exp14_pready; + wire exp14_pslverr; + wire [31:0] exp14_prdata; // Flash memory AHB signals wire flash_hsel; @@ -729,6 +774,7 @@ PAD_INOUT8MA_NOE uPAD_P1_15 ( // System Reset request can be from processor or watchdog // or when lockup happens and the control flag is set. assign cmsdk_SYSRESETREQ = SYSRESETREQ | WDOGRESETREQ | + ADPRESETREQ | (LOCKUP & LOCKUPRESET); `ifdef CORTEX_M0DESIGNSTART @@ -871,76 +917,130 @@ PAD_INOUT8MA_NOE uPAD_P1_15 ( `endif // ------------------------------- - // DMA Controller + // DMA Controller - ADP engine // ------------------------------- - // DMA interface not used in this example system - wire [DMA_CHANNEL_NUM-1:0] dma230_tie0; // tie off signal. + wire comio_tx_ready; + wire [7:0] comio_tx_data8; + wire comio_tx_valid; + + wire comio_rx_ready; + wire [7:0] comio_rx_data8; + wire comio_rx_valid; + + wire stdio_tx_ready; + wire [7:0] stdio_tx_data8; + wire stdio_tx_valid; - assign dma230_tie0 = {DMA_CHANNEL_NUM{1'b0}}; + wire stdio_rx_ready; + wire [7:0] stdio_rx_data8; + wire stdio_rx_valid; - // DMA done per channel - wire [DMA_CHANNEL_NUM-1:0] dma230_done_ch; + wire [7:0] adp_gpo8; + wire [7:0] adp_gpi8; + + assign adp_gpi8 = adp_gpo8; +assign ADPRESETREQ = adp_gpo8[0]; - generate if (INCLUDE_DMA != 0) begin : gen_pl230_udma // DMA controller present - pl230_udma u_pl230_udma ( + ADPcontrol_v1_0 u_ADP ( // Clock and Reset - .hclk (HCLKSYS), - .hresetn (HRESETn), + .ahb_hclk (HCLKSYS), + .ahb_hresetn (HRESETn), // DMA Control - .dma_req (dma230_tie0), - .dma_sreq (dma230_tie0), - .dma_waitonreq (dma230_tie0), - .dma_stall (1'b0), - .dma_active (), - .dma_done (dma230_done_ch), - .dma_err (dmac_err), + .com_rx_tready (comio_rx_ready), + .com_rx_tdata (comio_rx_data8), + .com_rx_tvalid (comio_rx_valid), + .com_tx_tready (comio_tx_ready), + .com_tx_tdata (comio_tx_data8), + .com_tx_tvalid (comio_tx_valid), + .stdio_rx_tready (stdio_rx_ready), + .stdio_rx_tdata (stdio_rx_data8), + .stdio_rx_tvalid (stdio_rx_valid), + .stdio_tx_tready (stdio_tx_ready), + .stdio_tx_tdata (stdio_tx_data8), + .stdio_tx_tvalid (stdio_tx_valid), + .gpo8 (adp_gpo8), + .gpi8 (adp_gpi8), // AHB-Lite Master Interface - .hready (dmac_hready), - .hresp (dmac_hresp), - .hrdata (dmac_hrdata), - .htrans (dmac_htrans), - .hwrite (dmac_hwrite), - .haddr (dmac_haddr), - .hsize (dmac_hsize), - .hburst (dmac_hburst), - .hmastlock (dmac_hmastlock), - .hprot (dmac_hprot), - .hwdata (dmac_hwdata), - // APB Slave Interface - .pclken (PCLKEN), - .psel (dmac_psel), - .pen (exp_penable), - .pwrite (exp_pwrite), - .paddr (exp_paddr[11:0]), - .pwdata (exp_pwdata[31:0]), - .prdata (dmac_prdata) + .ahb_hready (dmac_hready), + .ahb_hresp (dmac_hresp), + .ahb_hrdata (dmac_hrdata), + .ahb_htrans (dmac_htrans), + .ahb_hwrite (dmac_hwrite), + .ahb_haddr (dmac_haddr), + .ahb_hsize (dmac_hsize), + .ahb_hburst (dmac_hburst), + .ahb_hmastlock (dmac_hmastlock), + .ahb_hprot (dmac_hprot), + .ahb_hwdata (dmac_hwdata) ); - assign dmac_pready = 1'b1; - assign dmac_pslverr = 1'b0; - assign dmac_done = |dma230_done_ch; // OR all the DMA done together - - end else begin : gen_no_pl230_udma - // DMA controller not present - assign dmac_htrans = 2'b00; - assign dmac_hwrite = 1'b0; - assign dmac_haddr = 32'h00000000; - assign dmac_hsize = 3'b000; - assign dmac_hburst = 3'b000; - assign dmac_hmastlock = 1'b0; - assign dmac_hprot = 4'b0000; - assign dmac_hwdata = 32'h00000000; - - assign dmac_done = 1'b0; - assign dmac_err = 1'b0; - assign dmac_pready = 1'b1; - assign dmac_pslverr = 1'b0; - assign dmac_prdata = 32'h00000000; - assign dma230_done_ch = {DMA_CHANNEL_NUM{1'b0}}; - - end endgenerate + cmsdk_apb_uart_streamio u_apb_uart_com ( + .PCLK (PCLK), // Peripheral clock + .PCLKG (PCLKG), // Gated PCLK for bus + .PRESETn (PRESETn), // Reset + + .PSEL (exp14_psel), // APB interface inputs + .PADDR (exp_paddr[11:2]), + .PENABLE (exp_penable), + .PWRITE (exp_pwrite), + .PWDATA (exp_pwdata), + + .PRDATA (exp14_prdata), // APB interface outputs + .PREADY (exp14_pready), + .PSLVERR (exp14_pslverr), + + .ECOREVNUM (4'h0),// Engineering-change-order revision bits + + .RXD (1'b1), // Receive data + + .TXD ( ), // Transmit data + .TXEN ( ), // Transmit Enabled + + .BAUDTICK ( ), // Baud rate x16 tick output (for testing) + + .TX_VALID_o (stdio_rx_valid), + .TX_DATA8_o (stdio_rx_data8), + .TX_READY_i (stdio_rx_ready), + + .RX_VALID_i (stdio_tx_valid), + .RX_DATA8_i (stdio_tx_data8), + .RX_READY_o (stdio_tx_ready), + + .TXINT ( ), // Transmit Interrupt + .RXINT ( ), // Receive Interrupt + .TXOVRINT ( ), // Transmit Overrun Interrupt + .RXOVRINT ( ), // Receive Overrun Interrupt + .UARTINT ( ) // Combined Interrupt + ); + + wire [7:0] ft_clkdiv = 8'd03; + + ft1248_streamio_v1_0 # + (.FT1248_WIDTH (1), + .FT1248_CLKON(0) ) + u_ftdio_com ( + .clk (HCLKSYS), + .resetn (HRESETn), + .ft_clkdiv (ft_clkdiv ), + .ft_clk_o (ft_clk_o ), + .ft_ssn_o (ft_ssn_o ), + .ft_miso_i (ft_miso_i ), + .ft_miosio_o (ft_miosio_o ), + .ft_miosio_e (ft_miosio_e ), + .ft_miosio_z (ft_miosio_z ), + .ft_miosio_i (ft_miosio_i ), + .rxd_tready (comio_tx_ready), + .rxd_tdata (comio_tx_data8), + .rxd_tvalid (comio_tx_valid), + .rxd_tlast (1'b0), + .txd_tready (comio_rx_ready), + .txd_tdata (comio_rx_data8), + .txd_tvalid (comio_rx_valid), + .txd_tlast ( ) + ); + //--------------------------------------------------- // System design for example Cortex-M0/Cortex-M0+ MCU @@ -1092,14 +1192,26 @@ PAD_INOUT8MA_NOE uPAD_P1_15 ( .dmac_hprot (dmac_hprot), .dmac_hwdata (dmac_hwdata), // APB Slave Interface - .dmac_psel (dmac_psel), - .exp_penable (exp_penable), - .exp_pwrite (exp_pwrite), - .exp_paddr (exp_paddr[11:0]), - .exp_pwdata (exp_pwdata[31:0]), - .dmac_prdata (dmac_prdata), - .dmac_pready (1'b1), - .dmac_pslverr (1'b0), + .exp12_psel ( ), + .exp13_psel ( ), + .exp14_psel (exp14_psel), + .exp15_psel ( ), + .exp_penable (exp_penable), + .exp_pwrite (exp_pwrite), + .exp_paddr (exp_paddr[11:0]), + .exp_pwdata (exp_pwdata[31:0]), + .exp12_prdata (32'h00000000), + .exp12_pready (1'b1), + .exp12_pslverr (1'b0), + .exp13_prdata (32'h00000000), + .exp13_pready (1'b1), + .exp13_pslverr (1'b0), + .exp14_prdata (exp14_prdata), + .exp14_pready (exp14_pready), + .exp14_pslverr (exp14_pslverr), + .exp15_prdata (32'h00000000), + .exp15_pready (1'b1), + .exp15_pslverr (1'b0), .DFTSE (1'b0) ); @@ -1118,8 +1230,8 @@ PAD_INOUT8MA_NOE uPAD_P1_15 ( //---------------------------------------- cmsdk_ahb_rom #(.MEM_TYPE(ROM_MEM_TYPE), - .AW(16), // 64K bytes flash ROM -// .AW(15), // 32K bytes flash ROM -Dhry +// .AW(16), // 64K bytes flash ROM + .AW(13), // 8K bytes flash ROM -Dhry // .AW(10), // 1K bytes flash ROM - Hello .filename("image.hex"), .WS_N(`ARM_CMSDK_ROM_MEM_WS_N), @@ -1129,8 +1241,8 @@ cmsdk_ahb_rom .HCLK (HCLKSYS), .HRESETn (HRESETn), .HSEL (flash_hsel), // AHB inputs - .HADDR (HADDR[15:0]), -// .HADDR (HADDR[14:0]), +// .HADDR (HADDR[15:0]), + .HADDR (HADDR[12:0]), // .HADDR (HADDR[ 9:0]), .HTRANS (HTRANS), .HSIZE (HSIZE), @@ -1148,8 +1260,8 @@ cmsdk_ahb_rom //---------------------------------------- // Only use if BOOT_MEM_TYPE is not zero `ifdef SYNTHBOOTROM -//ahb_bootrom -ahb_bootrom__mangled +ahb_bootrom +//ahb_bootrom__mangled // #(.AW(10) ) // 1K bytes ROM u_ahb_bootloader ( .HCLK (HCLKSYS), diff --git a/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/cmsdk_mcu_system.v b/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/cmsdk_mcu_system.v index 074f4b9..16f7f9a 100644 --- a/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/cmsdk_mcu_system.v +++ b/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/cmsdk_mcu_system.v @@ -189,14 +189,26 @@ module cmsdk_mcu_system #( input wire [3 :0] dmac_hprot, input wire [31:0] dmac_hwdata, // APB Slave Interface - output wire dmac_psel, + output wire exp12_psel, + output wire exp13_psel, + output wire exp14_psel, + output wire exp15_psel, output wire exp_penable, output wire exp_pwrite, output wire [11:0] exp_paddr, output wire [31:0] exp_pwdata, - input wire [31:0] dmac_prdata, - input wire dmac_pready, - input wire dmac_pslverr, + input wire [31:0] exp12_prdata, + input wire exp12_pready, + input wire exp12_pslverr, + input wire [31:0] exp13_prdata, + input wire exp13_pready, + input wire exp13_pslverr, + input wire [31:0] exp14_prdata, + input wire exp14_pready, + input wire exp14_pslverr, + input wire [31:0] exp15_prdata, + input wire exp15_pready, + input wire exp15_pslverr, input wire DFTSE); // dummy scan enable port for synthesis @@ -926,7 +938,7 @@ u_cortexm0_ds cmsdk_apb_subsystem #( .APB_EXT_PORT12_ENABLE (0), .APB_EXT_PORT13_ENABLE (0), - .APB_EXT_PORT14_ENABLE (0), + .APB_EXT_PORT14_ENABLE (1), .APB_EXT_PORT15_ENABLE (INCLUDE_DMA), .INCLUDE_IRQ_SYNCHRONIZER(0), .INCLUDE_APB_TEST_SLAVE (1), @@ -970,27 +982,24 @@ u_cortexm0_ds .PWDATA (exp_pwdata[31:0]), .PENABLE (exp_penable), - .ext12_psel (), - .ext13_psel (), - .ext14_psel (), - .ext15_psel (dmac_psel), + .ext12_psel (exp12_psel), + .ext13_psel (exp13_psel), + .ext14_psel (exp14_psel), + .ext15_psel (exp15_psel), // Input from APB devices on APB expansion ports - .ext12_prdata (32'h00000000), - .ext12_pready (1'b1), - .ext12_pslverr (1'b0), - - .ext13_prdata (32'h00000000), - .ext13_pready (1'b1), - .ext13_pslverr (1'b0), - - .ext14_prdata (32'h00000000), - .ext14_pready (1'b1), - .ext14_pslverr (1'b0), - - .ext15_prdata (dmac_prdata), - .ext15_pready (dmac_pready), - .ext15_pslverr (dmac_pslverr), + .ext12_prdata (exp12_prdata), + .ext12_pready (exp12_pready), + .ext12_pslverr (exp12_pslverr), + .ext13_prdata (exp13_prdata), + .ext13_pready (exp13_pready), + .ext13_pslverr (exp13_pslverr), + .ext14_prdata (exp14_prdata), + .ext14_pready (exp14_pready), + .ext14_pslverr (exp14_pslverr), + .ext15_prdata (exp15_prdata), + .ext15_pready (exp15_pready), + .ext15_pslverr (exp15_pslverr), .APBACTIVE (APBACTIVE), // Status Output for clock gating diff --git a/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/cmsdk_uart_capture.v b/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/cmsdk_uart_capture.v index d4dd97c..cbc46f7 100644 --- a/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/cmsdk_uart_capture.v +++ b/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/cmsdk_uart_capture.v @@ -1,5 +1,5 @@ //----------------------------------------------------------------------------- -// customised example Cortex-M0 controller UART with file logging +// updated UART RXD capture with file logging // A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license. // // Contributors diff --git a/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/tb_cmsdk_mcu.v b/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/tb_cmsdk_mcu.v index d1d2e7c..6605105 100644 --- a/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/tb_cmsdk_mcu.v +++ b/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/tb_cmsdk_mcu.v @@ -186,8 +186,8 @@ SROM_Ax32 // Cortex-M0/Cortex-M0+ Microcontroller // -------------------------------------------------------------------------------- -// cmsdk_mcu_chip - cmsdk_mcu + cmsdk_mcu_chip +// cmsdk_mcu #(.CLKGATE_PRESENT (CLKGATE_PRESENT), .BE (BE), .BKPT (BKPT), // Number of breakpoint comparators @@ -357,10 +357,58 @@ reg baud_clk_del; .AUXCTRL () ); + // -------------------------------------------------------------------------------- + // FTDI IO capture + // -------------------------------------------------------------------------------- + // UART connection cross over for UART test - assign P1[0] = P1[3]; // UART 0 RXD = UART 1 TXD - assign P1[2] = P1[1]; // UART 1 RXD = UART 0 TXD +// assign P1[0] = P1[3]; // UART 0 RXD = UART 1 TXD +// assign P1[2] = P1[1]; // UART 1 RXD = UART 0 TXD + +wire ft_clk_out = P1[1]; +wire ft_miso_in; +assign P1[0] = ft_miso_in; +wire ft_ssn_out = P1[3]; + +// bufif0 (P1[2], ft_miosio_i, ft_miosio_z); +wire ft_clk2uart; +wire ft_rxd2uart; +wire ft_txd2uart; + + cmsdk_ft1248x1_adpio // #(.LOGFILENAME("uart2.log")) + u_ft1248_adpio( + .ft_clk_i (ft_clk_out), + .ft_ssn_i (ft_ssn_out), + .ft_miso_o (ft_miso_in), + .ft_miosio_io (P1[2]), + + .FTDI_CLK2UART_o (ft_clk2uart), + .FTDI_OP2UART_o (ft_rxd2uart), + .FTDI_IP2UART_o (ft_txd2uart) + ); + + cmsdk_uart_capture #(.LOGFILENAME("ft1248_op.log")) + u_cmsdk_uart_capture1( + .RESETn (NRST), + .CLK (ft_clk2uart), + .RXD (ft_rxd2uart), + .DEBUG_TESTER_ENABLE ( ), + .SIMULATIONEND (), // This signal set to 1 at the end of simulation. + .AUXCTRL () + ); + + cmsdk_uart_capture #(.LOGFILENAME("ft1248_ip.log")) + u_cmsdk_uart_capture2( + .RESETn (NRST), + .CLK (ft_clk2uart), + .RXD (ft_txd2uart), + .DEBUG_TESTER_ENABLE ( ), + .SIMULATIONEND (), // This signal set to 1 at the end of simulation. + .AUXCTRL () + ); + + // -------------------------------------------------------------------------------- // Tracking CPU with Tarmac trace support // -------------------------------------------------------------------------------- diff --git a/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/tbench_M0.vc b/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/tbench_M0.vc index 364812d..f346e85 100644 --- a/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/tbench_M0.vc +++ b/Cortex-M0/soclabs_demo/systems/cortex_m0_mcu/verilog/tbench_M0.vc @@ -6,7 +6,7 @@ // // David Flynn (d.w.flynn@soton.ac.uk) // -// Copyright © 2021, SoC Labs (www.soclabs.org) +// Copyright © 2021-2, SoC Labs (www.soclabs.org) //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- @@ -80,6 +80,7 @@ +incdir+../../../../../../arm-AAA-ip/Corstone-101_Foundation_IP/BP210-BU-00000-r1p1-00rel0/logical/cmsdk_apb_watchdog/verilog +incdir+../../../../../../arm-AAA-ip/Corstone-101_Foundation_IP/BP210-BU-00000-r1p1-00rel0/logical/models/memories/ + //// Optional PL230 Micro DMA controller - configure in local ../verilog/pl230_defs.v file //-y ../../../../../../arm-AAA-ip/DMA-230_MicroDMA_Controller/PL230-BU-00000-r0p0-02rel1/verilog +incdir+../../../../../../arm-AAA-ip/DMA-230_MicroDMA_Controller/PL230-BU-00000-r0p0-02rel1/verilog @@ -90,6 +91,12 @@ ../../../../../../arm-AAA-ip/DMA-230_MicroDMA_Controller/PL230-BU-00000-r0p0-02rel1/verilog/pl230_udma.v ../../../../../../arm-AAA-ip/DMA-230_MicroDMA_Controller/PL230-BU-00000-r0p0-02rel1/verilog/pl230_undefs.v + +../../../../../IPLIB/FT1248_streamio_v1_0/ft1248_streamio_v1_0.v +../../../../../IPLIB/ADPcontrol_v1_0/ADPcontrol_v1_0.v +../../../../../IPLIB/ADPcontrol_v1_0/ADPmanager.v +../verilog/cmsdk_apb_uart_streamio.v + // ============= Cortex-M0 Module search path ============= -y ../../../../../../arm-AAA-ip/Cortex-M0/AT510-BU-00000-r0p0-03rel3/logical/cortexm0/verilog diff --git a/IPLIB/ADPcontrol_v1_0/ADPcontrol_v1_0.v b/IPLIB/ADPcontrol_v1_0/ADPcontrol_v1_0.v new file mode 100755 index 0000000..7b8967c --- /dev/null +++ b/IPLIB/ADPcontrol_v1_0/ADPcontrol_v1_0.v @@ -0,0 +1,103 @@ +//----------------------------------------------------------------------------- +// top-level soclabs ASCII Debug Protocol controller +// A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license. +// +// Contributors +// +// David Flynn (d.w.flynn@soton.ac.uk) +// +// Copyright © 2021-2, SoC Labs (www.soclabs.org) +//----------------------------------------------------------------------------- + + + module ADPcontrol_v1_0 # + ( + // Users to add parameters here + parameter PROMPT_CHAR = "]" + + // User parameters ends + // Do not modify the parameters beyond this line + + ) + ( + // Users to add ports here + + // User ports ends + // Do not modify the ports beyond this line + + // Ports of Axi Slave Bus Interface com_rx + input wire ahb_hclk, + input wire ahb_hresetn, + + output wire com_rx_tready, + input wire [7 : 0] com_rx_tdata, + input wire com_rx_tvalid, + + // Ports of Axi Master Bus Interface com_tx + output wire com_tx_tvalid, + output wire [7 : 0] com_tx_tdata, + input wire com_tx_tready, + + // Ports of Axi Slave Bus Interface stdio_rx + output wire stdio_rx_tready, + input wire [7 : 0] stdio_rx_tdata, + input wire stdio_rx_tvalid, + + // Ports of Axi Master Bus Interface stdio_tx + output wire stdio_tx_tvalid, + output wire [7 : 0] stdio_tx_tdata, + input wire stdio_tx_tready, + + output wire [7 : 0] gpo8, + input wire [7 : 0] gpi8, + + output wire [31:0] ahb_haddr , + output wire [ 2:0] ahb_hburst , + output wire ahb_hmastlock, + output wire [ 3:0] ahb_hprot , + output wire [ 2:0] ahb_hsize , + output wire [ 1:0] ahb_htrans , + output wire [31:0] ahb_hwdata , + output wire ahb_hwrite , + input wire [31:0] ahb_hrdata , + input wire ahb_hready , + input wire ahb_hresp + ); + + // Add user logic here + +ADPmanager + #(.PROMPT_CHAR (PROMPT_CHAR)) + ADPmanager( + .HCLK (ahb_hclk ), + .HRESETn (ahb_hresetn ), + .HADDR32_o (ahb_haddr ), + .HBURST3_o (ahb_hburst ), + .HMASTLOCK_o (ahb_hmastlock ), + .HPROT4_o (ahb_hprot ), + .HSIZE3_o (ahb_hsize ), + .HTRANS2_o (ahb_htrans ), + .HWDATA32_o (ahb_hwdata ), + .HWRITE_o (ahb_hwrite ), + .HRDATA32_i (ahb_hrdata ), + .HREADY_i (ahb_hready ), + .HRESP_i (ahb_hresp ), + .GPO8_o (gpo8 ), + .GPI8_i (gpi8 ), + .COMRX_TREADY_o(com_rx_tready), + .COMRX_TDATA_i(com_rx_tdata), + .COMRX_TVALID_i(com_rx_tvalid), + .STDRX_TREADY_o(stdio_rx_tready), + .STDRX_TDATA_i(stdio_rx_tdata), + .STDRX_TVALID_i(stdio_rx_tvalid), + .COMTX_TVALID_o(com_tx_tvalid), + .COMTX_TDATA_o(com_tx_tdata), + .COMTX_TREADY_i(com_tx_tready), + .STDTX_TVALID_o(stdio_tx_tvalid), + .STDTX_TDATA_o(stdio_tx_tdata), + .STDTX_TREADY_i(stdio_tx_tready) + + ); + + +endmodule diff --git a/IPLIB/ADPcontrol_v1_0/ADPmanager.v b/IPLIB/ADPcontrol_v1_0/ADPmanager.v new file mode 100755 index 0000000..f4747ae --- /dev/null +++ b/IPLIB/ADPcontrol_v1_0/ADPmanager.v @@ -0,0 +1,786 @@ +//----------------------------------------------------------------------------- +// soclabs ASCII Debug Protocol controller +// A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license. +// +// Contributors +// +// David Flynn (d.w.flynn@soton.ac.uk) +// +// Copyright © 2021-2, SoC Labs (www.soclabs.org) +//----------------------------------------------------------------------------- + + +//`define ADPBASIC 1 + +module ADPmanager // AHB initiator interface + #(parameter PROMPT_CHAR = "]" + ) + ( input wire HCLK, + input wire HRESETn, + output wire [31:0] HADDR32_o, + output wire [ 2:0] HBURST3_o, + output wire HMASTLOCK_o, + output wire [ 3:0] HPROT4_o, + output wire [ 2:0] HSIZE3_o, + output wire [ 1:0] HTRANS2_o, + output wire [31:0] HWDATA32_o, + output wire HWRITE_o, + input wire [31:0] HRDATA32_i, + input wire HREADY_i, + input wire HRESP_i, +// COMIO interface + output wire [ 7:0] GPO8_o, + input wire [ 7:0] GPI8_i, +// input wire COM_RXE_i, + input wire [ 7:0] COMRX_TDATA_i, + input wire COMRX_TVALID_i, + output wire COMRX_TREADY_o, +// input wire COM_TXF_i, + output wire [ 7:0] COMTX_TDATA_o, + output wire COMTX_TVALID_o, + input wire COMTX_TREADY_i, +// STDIO interface +// input wire STDOUT_RXE_i, + input wire [ 7:0] STDRX_TDATA_i, + input wire STDRX_TVALID_i, + output wire STDRX_TREADY_o, +// input wire STDIN_TXF_i + output wire [ 7:0] STDTX_TDATA_o, + output wire STDTX_TVALID_o, + input wire STDTX_TREADY_i +); + +wire COM_RXE_i = !COMRX_TVALID_i; +wire COM_TXF_i = !COMTX_TREADY_i; + +//wire adp_rx_req = COMRX_TVALID_i & COMRX_TREADY_o; +//wire std_rx_req = STDRX_TVALID_i & STDRX_TREADY_o; + + +wire STD_TXF_i = !STDTX_TREADY_i; +wire STD_RXE_i = !STDRX_TVALID_i; + +`ifdef ADPBASIC + localparam BANNERHEX = 32'h50c1ab01; +`else + localparam BANNERHEX = 32'h50c1ab02; +`endif + +localparam CMD_bad = 4'b0000; +localparam CMD_A = 4'b0001; // set address +`ifndef ADPBASIC +localparam CMD_B = 4'b1000; // Binary upload (wordocunt) from addr++ +localparam CMD_M = 4'b1010; // set read mask +localparam CMD_P = 4'b1011; // Poll hardware (count) +localparam CMD_V = 4'b1100; // match value +localparam CMD_Z = 4'b1101; // Zero-fill (wordocunt) from addr++ +`endif +localparam CMD_C = 4'b1001; // Control +localparam CMD_R = 4'b0010; // read word, addr++ +localparam CMD_S = 4'b0011; // Status/STDIN +localparam CMD_W = 4'b0100; // write word, addr++ +localparam CMD_X = 4'b0101; // exit + + +function FNvalid_adp_entry; // Escape char +input [7:0] char8; + FNvalid_adp_entry = (char8[7:0] == 8'h1b); +endfunction + +function [3:0] FNvalid_cmd; +input [7:0] char8; +case (char8[7:0]) +"A": FNvalid_cmd = CMD_A; +"a": FNvalid_cmd = CMD_A; +"C": FNvalid_cmd = CMD_C; +"c": FNvalid_cmd = CMD_C; +"R": FNvalid_cmd = CMD_R; +"r": FNvalid_cmd = CMD_R; +"S": FNvalid_cmd = CMD_S; +"s": FNvalid_cmd = CMD_S; +"W": FNvalid_cmd = CMD_W; +"w": FNvalid_cmd = CMD_W; +"X": FNvalid_cmd = CMD_X; +"x": FNvalid_cmd = CMD_X; +`ifndef ADPBASIC +"B": FNvalid_cmd = CMD_B; +"b": FNvalid_cmd = CMD_B; +"M": FNvalid_cmd = CMD_M; +"m": FNvalid_cmd = CMD_M; +"P": FNvalid_cmd = CMD_P; +"p": FNvalid_cmd = CMD_P; +"V": FNvalid_cmd = CMD_V; +"v": FNvalid_cmd = CMD_V; +"Z": FNvalid_cmd = CMD_Z; +"z": FNvalid_cmd = CMD_Z; +`endif +default: + FNvalid_cmd = 0; +endcase +endfunction + +function FNvalid_space; // space or tab char +input [7:0] char8; + FNvalid_space = ((char8[7:0] == 8'h20) || (char8[7:0] == 8'h09)); +endfunction + +function FNnull; // space or tab char +input [7:0] char8; + FNnull = (char8[7:0] == 8'h00); +endfunction + +function FNexit; // EOF +input [7:0] char8; + FNexit = ((char8[7:0] == 8'h04) || (char8[7:0] == 8'h00)); +endfunction + +function FNvalid_EOL; // CR or LF +input [7:0] char8; + FNvalid_EOL = ((char8[7:0] == 8'h0a) || (char8[7:0] == 8'h0d)); +endfunction + +function FNuppercase; +input [7:0] char8; + FNuppercase = (char8[6]) ? (char8 & 8'h5f) : (char8); +endfunction + +function [63:0] FNBuild_param64_hexdigit; +input [63:0] param64; +input [7:0] char8; +case (char8[7:0]) +"\t":FNBuild_param64_hexdigit = 64'b0; // tab starts new (zeroed) param64 +" ": FNBuild_param64_hexdigit = 64'b0; // space starts new (zeroed) param64 +"x": FNBuild_param64_hexdigit = 64'b0; // hex prefix starts new (zeroed) param64 +"X": FNBuild_param64_hexdigit = 64'b0; // hex prefix starts new (zeroed) param64 +"0": FNBuild_param64_hexdigit = {param64[59:0],4'b0000}; +"1": FNBuild_param64_hexdigit = {param64[59:0],4'b0001}; +"2": FNBuild_param64_hexdigit = {param64[59:0],4'b0010}; +"3": FNBuild_param64_hexdigit = {param64[59:0],4'b0011}; +"4": FNBuild_param64_hexdigit = {param64[59:0],4'b0100}; +"5": FNBuild_param64_hexdigit = {param64[59:0],4'b0101}; +"6": FNBuild_param64_hexdigit = {param64[59:0],4'b0110}; +"7": FNBuild_param64_hexdigit = {param64[59:0],4'b0111}; +"8": FNBuild_param64_hexdigit = {param64[59:0],4'b1000}; +"9": FNBuild_param64_hexdigit = {param64[59:0],4'b1001}; +"A": FNBuild_param64_hexdigit = {param64[59:0],4'b1010}; +"B": FNBuild_param64_hexdigit = {param64[59:0],4'b1011}; +"C": FNBuild_param64_hexdigit = {param64[59:0],4'b1100}; +"D": FNBuild_param64_hexdigit = {param64[59:0],4'b1101}; +"E": FNBuild_param64_hexdigit = {param64[59:0],4'b1110}; +"F": FNBuild_param64_hexdigit = {param64[59:0],4'b1111}; +"a": FNBuild_param64_hexdigit = {param64[59:0],4'b1010}; +"b": FNBuild_param64_hexdigit = {param64[59:0],4'b1011}; +"c": FNBuild_param64_hexdigit = {param64[59:0],4'b1100}; +"d": FNBuild_param64_hexdigit = {param64[59:0],4'b1101}; +"e": FNBuild_param64_hexdigit = {param64[59:0],4'b1110}; +"f": FNBuild_param64_hexdigit = {param64[59:0],4'b1111}; +default: FNBuild_param64_hexdigit = param64; // EOL etc returns param64 unchanged +endcase +endfunction + +function [63:0] FNBuild_param64_byte; +input [63:0] param64; +input [7:0] byte; + FNBuild_param64_byte = {byte[7:0], param64[63:08]}; +endfunction + +function [31:0] FNBuild_param32_hexdigit; +input [31:0] param32; +input [7:0] char8; +case (char8[7:0]) +"\t":FNBuild_param32_hexdigit = 32'b0; // tab starts new (zeroed) param32 +" ": FNBuild_param32_hexdigit = 32'b0; // space starts new (zeroed) param32 +"x": FNBuild_param32_hexdigit = 32'b0; // hex prefix starts new (zeroed) param32 +"X": FNBuild_param32_hexdigit = 32'b0; // hex prefix starts new (zeroed) param32 +"0": FNBuild_param32_hexdigit = {param32[27:0],4'b0000}; +"1": FNBuild_param32_hexdigit = {param32[27:0],4'b0001}; +"2": FNBuild_param32_hexdigit = {param32[27:0],4'b0010}; +"3": FNBuild_param32_hexdigit = {param32[27:0],4'b0011}; +"4": FNBuild_param32_hexdigit = {param32[27:0],4'b0100}; +"5": FNBuild_param32_hexdigit = {param32[27:0],4'b0101}; +"6": FNBuild_param32_hexdigit = {param32[27:0],4'b0110}; +"7": FNBuild_param32_hexdigit = {param32[27:0],4'b0111}; +"8": FNBuild_param32_hexdigit = {param32[27:0],4'b1000}; +"9": FNBuild_param32_hexdigit = {param32[27:0],4'b1001}; +"A": FNBuild_param32_hexdigit = {param32[27:0],4'b1010}; +"B": FNBuild_param32_hexdigit = {param32[27:0],4'b1011}; +"C": FNBuild_param32_hexdigit = {param32[27:0],4'b1100}; +"D": FNBuild_param32_hexdigit = {param32[27:0],4'b1101}; +"E": FNBuild_param32_hexdigit = {param32[27:0],4'b1110}; +"F": FNBuild_param32_hexdigit = {param32[27:0],4'b1111}; +"a": FNBuild_param32_hexdigit = {param32[27:0],4'b1010}; +"b": FNBuild_param32_hexdigit = {param32[27:0],4'b1011}; +"c": FNBuild_param32_hexdigit = {param32[27:0],4'b1100}; +"d": FNBuild_param32_hexdigit = {param32[27:0],4'b1101}; +"e": FNBuild_param32_hexdigit = {param32[27:0],4'b1110}; +"f": FNBuild_param32_hexdigit = {param32[27:0],4'b1111}; +default: FNBuild_param32_hexdigit = param32; // EOL etc returns param32 unchanged +endcase +endfunction + +function [31:0] FNBuild_param32_byte; +input [31:0] param32; +input [7:0] byte; + FNBuild_param32_byte = {byte[7:0], param32[31:08]}; +endfunction + + + +function [7:0] FNmap_hex_digit; +input [3:0] nibble; +case (nibble[3:0]) +4'b0000: FNmap_hex_digit = "0"; +4'b0001: FNmap_hex_digit = "1"; +4'b0010: FNmap_hex_digit = "2"; +4'b0011: FNmap_hex_digit = "3"; +4'b0100: FNmap_hex_digit = "4"; +4'b0101: FNmap_hex_digit = "5"; +4'b0110: FNmap_hex_digit = "6"; +4'b0111: FNmap_hex_digit = "7"; +4'b1000: FNmap_hex_digit = "8"; +4'b1001: FNmap_hex_digit = "9"; +4'b1010: FNmap_hex_digit = "a"; +4'b1011: FNmap_hex_digit = "b"; +4'b1100: FNmap_hex_digit = "c"; +4'b1101: FNmap_hex_digit = "d"; +4'b1110: FNmap_hex_digit = "e"; +4'b1111: FNmap_hex_digit = "f"; +default: FNmap_hex_digit = "0"; +endcase +endfunction + + +// as per Vivado synthesis mapping +`ifdef ADPFSMDESIGN +localparam ADP_WRITEHEX = 6'b000000 ; +localparam ADP_WRITEHEXS = 6'b000001 ; +localparam ADP_WRITEHEX9 = 6'b000010 ; +localparam ADP_WRITEHEX8 = 6'b000011 ; +localparam ADP_WRITEHEX7 = 6'b000100 ; +localparam ADP_WRITEHEX6 = 6'b000101 ; +localparam ADP_WRITEHEX5 = 6'b000110 ; +localparam ADP_WRITEHEX4 = 6'b000111 ; +localparam ADP_WRITEHEX3 = 6'b001000 ; +localparam ADP_WRITEHEX2 = 6'b001001 ; +localparam ADP_WRITEHEX1 = 6'b001010 ; +localparam ADP_WRITEHEX0 = 6'b001011 ; +localparam ADP_LINEACK = 6'b001101 ; +localparam ADP_LINEACK2 = 6'b110010 ; +localparam ADP_PROMPT = 6'b001110 ; +localparam ADP_IOCHK = 6'b001111 ; +localparam ADP_RXCMD = 6'b010000 ; +localparam ADP_RXPARAM = 6'b010010 ; +localparam ADP_ACTION = 6'b010011 ; +localparam ADP_READ = 6'b010001 ; +localparam ADP_SYSCHK = 6'b010100 ; +localparam ADP_STDIN = 6'b010101 ; +localparam ADP_SYSCTL = 6'b010110 ; +localparam ADP_WRITE = 6'b010111 ; +localparam ADP_EXIT = 6'b011000 ; +localparam STD_IOCHK = 6'b011001 ; +localparam STD_RXD1 = 6'b011010 ; +localparam STD_RXD2 = 6'b011011 ; +localparam STD_TXD1 = 6'b011101 ; +localparam STD_TXD2 = 6'b011110 ; +localparam ADP_BCTRL = 6'b011111 ; +localparam ADP_BREADB0 = 6'b100000 ; +localparam ADP_BREADB1 = 6'b100001 ; +localparam ADP_BREADB2 = 6'b100010 ; +localparam ADP_BREADB3 = 6'b100011 ; +localparam ADP_BWRITE = 6'b100100 ; +localparam ADP_POLL = 6'b100101 ; +localparam ADP_POLL1 = 6'b100110 ; +localparam ADP_POLL2 = 6'b100111 ; +localparam ADP_ZCTRL = 6'b101110 ; +localparam ADP_ZWRITE = 6'b101111 ; +localparam ADP_ECHOCMD = 6'b110000 ; +localparam ADP_ECHOCMDSP = 6'b110001 ; +localparam ADP_UNKNOWN = 6'b101000 ; +localparam ADP_STDOUT = 6'b101010 ; +localparam ADP_STDOUT1 = 6'b101011 ; +localparam ADP_STDOUT2 = 6'b101100 ; +localparam ADP_STDOUT3 = 6'b101101 ; +reg [5:0] adp_state ; +`else +// one-hot encoded explicitly +localparam ADP_WRITEHEX = 48'b000000000000000000000000000000000000000000000001 ; // = 6'b000000 +localparam ADP_WRITEHEXS = 48'b000000000000000000000000000000000000000000000010 ; // = 6'b000001 +localparam ADP_WRITEHEX9 = 48'b000000000000000000000000000000000000000000000100 ; // = 6'b000010 +localparam ADP_WRITEHEX8 = 48'b000000000000000000000000000000000000000000001000 ; // = 6'b000011 +localparam ADP_WRITEHEX7 = 48'b000000000000000000000000000000000000000000010000 ; // = 6'b000100 +localparam ADP_WRITEHEX6 = 48'b000000000000000000000000000000000000000000100000 ; // = 6'b000101 +localparam ADP_WRITEHEX5 = 48'b000000000000000000000000000000000000000001000000 ; // = 6'b000110 +localparam ADP_WRITEHEX4 = 48'b000000000000000000000000000000000000000010000000 ; // = 6'b000111 +localparam ADP_WRITEHEX3 = 48'b000000000000000000000000000000000000000100000000 ; // = 6'b001000 +localparam ADP_WRITEHEX2 = 48'b000000000000000000000000000000000000001000000000 ; // = 6'b001001 +localparam ADP_WRITEHEX1 = 48'b000000000000000000000000000000000000010000000000 ; // = 6'b001010 +localparam ADP_WRITEHEX0 = 48'b000000000000000000000000000000000000100000000000 ; // = 6'b001011 +localparam ADP_LINEACK = 48'b000000000000000000000000000000000001000000000000 ; // = 6'b001101 +localparam ADP_LINEACK2 = 48'b000000000000000000000000000000000010000000000000 ; // = 6'b110010 +localparam ADP_PROMPT = 48'b000000000000000000000000000000000100000000000000 ; // = 6'b001110 +localparam ADP_IOCHK = 48'b000000000000000000000000000000001000000000000000 ; // = 6'b001111 +localparam ADP_RXCMD = 48'b000000000000000000000000000000010000000000000000 ; // = 6'b010000 +localparam ADP_RXPARAM = 48'b000000000000000000000000000000100000000000000000 ; // = 6'b010010 +localparam ADP_ACTION = 48'b000000000000000000000000000001000000000000000000 ; // = 6'b010011 +localparam ADP_READ = 48'b000000000000000000000000000010000000000000000000 ; // = 6'b010001 +localparam ADP_SYSCHK = 48'b000000000000000000000000000100000000000000000000 ; // = 6'b010100 +localparam ADP_STDIN = 48'b000000000000000000000000001000000000000000000000 ; // = 6'b010101 +localparam ADP_SYSCTL = 48'b000000000000000000000000010000000000000000000000 ; // = 6'b010110 +localparam ADP_WRITE = 48'b000000000000000000000000100000000000000000000000 ; // = 6'b010111 +localparam ADP_EXIT = 48'b000000000000000000000001000000000000000000000000 ; // = 6'b011000 +localparam STD_IOCHK = 48'b000000000000000000000010000000000000000000000000 ; // = 6'b011001 +localparam STD_RXD1 = 48'b000000000000000000000100000000000000000000000000 ; // = 6'b011010 +localparam STD_RXD2 = 48'b000000000000000000001000000000000000000000000000 ; // = 6'b011011 +localparam STD_TXD1 = 48'b000000000000000000010000000000000000000000000000 ; // = 6'b011101 +localparam STD_TXD2 = 48'b000000000000000000100000000000000000000000000000 ; // = 6'b011110 +localparam ADP_BCTRL = 48'b000000000000000001000000000000000000000000000000 ; // = 6'b011111 +localparam ADP_BREADB0 = 48'b000000000000000010000000000000000000000000000000 ; // = 6'b100000 +localparam ADP_BREADB1 = 48'b000000000000000100000000000000000000000000000000 ; // = 6'b100001 +localparam ADP_BREADB2 = 48'b000000000000001000000000000000000000000000000000 ; // = 6'b100010 +localparam ADP_BREADB3 = 48'b000000000000010000000000000000000000000000000000 ; // = 6'b100011 +localparam ADP_BWRITE = 48'b000000000000100000000000000000000000000000000000 ; // = 6'b100100 +localparam ADP_POLL = 48'b000000000001000000000000000000000000000000000000 ; // = 6'b100101 +localparam ADP_POLL1 = 48'b000000000010000000000000000000000000000000000000 ; // = 6'b100110 +localparam ADP_POLL2 = 48'b000000000100000000000000000000000000000000000000 ; // = 6'b100111 +localparam ADP_ZCTRL = 48'b000000001000000000000000000000000000000000000000 ; // = 6'b101110 +localparam ADP_ZWRITE = 48'b000000010000000000000000000000000000000000000000 ; // = 6'b101111 +localparam ADP_ECHOCMD = 48'b000000100000000000000000000000000000000000000000 ; // = 6'b110000 +localparam ADP_ECHOCMDSP = 48'b000001000000000000000000000000000000000000000000 ; // = 6'b110001 +localparam ADP_UNKNOWN = 48'b000010000000000000000000000000000000000000000000 ; // = 6'b101000 +localparam ADP_STDOUT = 48'b000100000000000000000000000000000000000000000000 ; // = 6'b101010 +localparam ADP_STDOUT1 = 48'b001000000000000000000000000000000000000000000000 ; // = 6'b101011 +localparam ADP_STDOUT2 = 48'b010000000000000000000000000000000000000000000000 ; // = 6'b101100 +localparam ADP_STDOUT3 = 48'b100000000000000000000000000000000000000000000000 ; // = 6'b101101 +reg [47:0] adp_state ; +`endif + +reg [31:0] adp_bus_data; +reg banner ; +reg com_tx_req ; +reg [7:0] com_tx_byte ; +reg com_rx_ack ; +reg std_tx_req ; +reg [ 7:0] std_tx_byte; +reg std_rx_ack ; +reg adp_bus_req ; +reg adp_bus_write ; +reg [7:0] adp_cmd ; +reg [31:0] adp_param ; +reg [31:0] adp_addr ; +reg adp_addr_inc; +reg [31:0] adp_sys ; + +assign GPO8_o = adp_sys[7:0]; + +// ADP RX stream +wire com_rx_req = COMRX_TVALID_i; +wire [ 7:0] com_rx_byte = COMRX_TDATA_i; +assign COMRX_TREADY_o = com_rx_ack; +// ADP TX stream +wire com_tx_ack = COMTX_TREADY_i; +assign COMTX_TDATA_o = com_tx_byte; +assign COMTX_TVALID_o = com_tx_req; +// STD RX stream (from STDOUT) +wire std_rx_req = STDRX_TVALID_i; +wire [ 7:0] std_rx_byte = STDRX_TDATA_i; +assign STDRX_TREADY_o = std_rx_ack; +// STD TX stream (to STDIN) +wire std_tx_ack = STDTX_TREADY_i; +assign STDTX_TDATA_o = std_tx_byte; +assign STDTX_TVALID_o = std_tx_req; + +//AMBA AHB master as "stream" interface +reg ahb_dphase; +wire ahb_aphase = adp_bus_req & !ahb_dphase; +wire adp_bus_ack = ahb_dphase & HREADY_i; +// control pipe +always @(posedge HCLK or negedge HRESETn) + if(!HRESETn) + ahb_dphase <= 0; + else if (HREADY_i) + ahb_dphase <= (ahb_aphase); + +assign HADDR32_o = adp_addr; +assign HBURST3_o = 3'b001; // "INCR" burst signalled whenever transfer; +assign HMASTLOCK_o = 1'b0; +assign HPROT4_o[3:0] = {1'b0, 1'b0, 1'b1, 1'b1}; +assign HSIZE3_o[2:0] = {1'b0, 2'b10}; +assign HTRANS2_o = {ahb_aphase,1'b0}; // non-seq +assign HWDATA32_o = adp_bus_data; +assign HWRITE_o = adp_bus_write; + + +`ifndef ADPBASIC +//reg [63:0] adp_bctrl64; +reg [31:0] adp_bctrl; +reg [31:0] adp_val; +reg [31:0] adp_mask; +reg [31:0] adp_poll; +reg [31:0] adp_count; +reg adp_count_dec ; +wire adp_delay_done; +wire adp_bctrl_done; +wire adp_bctrl_zero; +wire poll2_loop_next; +`endif + +// ADP_control flags in the 'C' control field +wire adp_disable; +wire adp_stdin_wait; + +// commnon interface handshake terms +wire com_rx_done = COMRX_TVALID_i & COMRX_TREADY_o; +wire com_tx_done = COMTX_TVALID_o & COMTX_TREADY_i; +wire std_rx_done = STDRX_TVALID_i & STDRX_TREADY_o; +wire std_tx_done = STDTX_TVALID_o & STDTX_TREADY_i; +wire adp_bus_done = (adp_bus_req & adp_bus_ack); + +// common task to set up for next state +task ADP_LINEACK_next; // prepare newline TX (and cancel any startup banner) +// begin com_tx_req <= 1; com_tx_byte <= 8'h0A; banner <= 0; adp_state <= ADP_LINEACK; end + begin com_tx_req <= 1; com_tx_byte <= 8'h0A; adp_state <= ADP_LINEACK; end +endtask +task ADP_PROMPT_next; // prepare prompt TX + begin com_tx_req <= 1; com_tx_byte <= PROMPT_CHAR; adp_state <= ADP_PROMPT; end +endtask +task ADP_BUSWRITEINC_next; // prepare bus write and addr++ on completion + begin adp_bus_req <=1; adp_bus_write <=1; adp_addr_inc <=1; end +endtask +task ADP_BUSREADINC_next; // prepare bus read and addr++ on completion + begin adp_bus_req <=1; adp_bus_write <=0; adp_addr_inc <=1; end +endtask + +task ADP_hexdigit_next; // output nibble +input [3:0] nibble; + begin com_tx_req <= 1; com_tx_byte <= FNmap_hex_digit(nibble[3:0]); end +endtask +task ADP_txchar_next; // output char +input [7:0] byte; + begin com_tx_req<= 1; com_tx_byte <= byte; end +endtask + +task com_rx_nxt; com_rx_ack <=1; endtask + +function FNcount_down_zero_next; // param about to be zero +input [31:0] counter; + FNcount_down_zero_next = !(|counter[31:1]); +endfunction + +always @(posedge HCLK or negedge HRESETn) + if(!HRESETn) begin + adp_state <= ADP_WRITEHEX ; + adp_bus_data <= BANNERHEX; + banner <= 1; // start-up HEX message + com_tx_req <= 0; // default no TX req + com_rx_ack <= 0; // default no RX ack + std_tx_req <= 0; // default no TX req + std_rx_ack <= 0; // default no RX ack + adp_bus_req <= 0; // default no bus transaction + adp_cmd <= 0; + adp_param <= 0; + adp_addr <= 0; + adp_addr_inc <= 0; + adp_bus_write<= 0; +`ifndef ADPBASIC + adp_count <= 0; + adp_count_dec<= 0; + adp_val <= 0; + adp_mask <= 0; + adp_sys <= 0; +`endif + end else begin // default states + adp_state <= adp_state; // default to hold current state + com_tx_req <= 0; // default no TX req + com_rx_ack <= 0; // default no RX ack + std_tx_req <= 0; // default no TX req + std_rx_ack <= 0; // default no RX ack + adp_bus_req <= 0; // default no bus transaction + adp_addr <= (adp_addr_inc & adp_bus_done) ? adp_addr + 4 : adp_addr; // address++ + adp_addr_inc <= 0; +`ifndef ADPBASIC + adp_count <= (adp_count_dec & adp_bus_done & |adp_count) ? adp_count - 1 : adp_count; // param-- + adp_count_dec<= 0; +`endif + case (adp_state) +// >>>>>>>>>>>>>>>> STDIO BYPASS >>>>>>>>>>>>>>>>>>>>>> + STD_IOCHK: // check for commsrx or STDOUT and not busy service, else loop back + if (com_rx_req) begin com_rx_ack <= 1; adp_state <= STD_RXD1; end // input char pending for STDIN +// else if (com_tx_ack & std_rx_req) begin std_rx_ack <= 1; adp_state <= STD_TXD1; end // STDOUT char pending and not busy + else if (std_rx_req) begin std_rx_ack <= 1; adp_state <= STD_TXD1; end // STDOUT char pending and not busy + STD_TXD1: // get STD out char + if (std_rx_done) + begin com_tx_byte <= std_rx_byte; com_tx_req <= 1; adp_state <= STD_TXD2; end + else std_rx_ack <= 1; // extend + STD_TXD2: // output char to ADP channel + if (com_tx_done) begin adp_state <= STD_IOCHK; end + else com_tx_req <= 1; // extend + STD_RXD1: // read rx char and check for ADP entry else STDIN ** + if (com_rx_done) begin + if (FNvalid_adp_entry(com_rx_byte)) + begin ADP_txchar_next(8'h0A); adp_state <= ADP_LINEACK; end // ADP prompt + else if (std_tx_ack) + begin std_tx_byte <= com_rx_byte; std_tx_req <= 1; adp_state <= STD_RXD2; end + else adp_state <= STD_IOCHK; // otherwise discard STDIN char and process OP data if blocked + end else com_rx_ack <= 1; // extend + STD_RXD2: // get STD in char + if (std_tx_done) begin adp_state <= STD_IOCHK; end + else std_tx_req <= 1; // extend + +// >>>>>>>>>>>>>>>> ADP Monitor >>>>>>>>>>>>>>>>>>>>>> + ADP_PROMPT: // transition after reset deassertion + if (com_tx_done) begin adp_state <= ADP_IOCHK; end + else com_tx_req <= 1; // extend + + ADP_IOCHK: // check for commsrx or STDOUT and not busy service, else loop back + if (com_rx_req) begin com_rx_ack <= 1; adp_state <= ADP_RXCMD; end + else if (com_tx_ack & std_rx_req) begin com_tx_byte <= "<"; com_tx_req <= 1; adp_state <= ADP_STDOUT; end +// else if (std_rx_req) begin com_tx_byte <= "<"; com_tx_req <= 1; adp_state <= ADP_STDOUT; end + +// >>>>>>>>>>>>>>>> ADP <STDOUT> >>>>>>>>>>>>>>>>>>>>>> + ADP_STDOUT: // output "<" + if (com_tx_done) begin std_rx_ack <= 1; adp_state <= ADP_STDOUT1; end + else com_tx_req <= 1; // extend stream request if not ready + ADP_STDOUT1: // get STD out char + if (std_rx_done) begin com_tx_byte <= std_rx_byte; com_tx_req <= 1; adp_state <= ADP_STDOUT2; end + else std_rx_ack <= 1; // else extend + ADP_STDOUT2: // output char + if (com_tx_done) begin com_tx_byte <= ">"; com_tx_req <= 1; adp_state <= ADP_STDOUT3; end + else com_tx_req <= 1; // else extend + ADP_STDOUT3: // output ">" + if (com_tx_done) begin adp_state <= ADP_IOCHK; end + else com_tx_req <= 1; // else extend + +// >>>>>>>>>>>>>>>> ADP COMMAND PARSING >>>>>>>>>>>>>>>>>>>>>> + ADP_RXCMD: // read and save ADP command + if (com_rx_done) begin + if (FNexit(com_rx_byte)) adp_state <= STD_IOCHK; // immediate exit + else if (FNvalid_space(com_rx_byte)) com_rx_ack <= 1; // retry for a command + else if (FNvalid_EOL(com_rx_byte)) begin adp_cmd <= "?"; adp_state <= ADP_ACTION; end // no command, skip param + else begin adp_cmd <= com_rx_byte; adp_param <= 32'hffffffff; com_rx_ack <= 1; adp_state <= ADP_RXPARAM; end // get optional parameter + end + else com_rx_ack <= 1; // extend stream request if not ready + ADP_RXPARAM: // read and build hex parameter + if (com_rx_done) begin // RX byte + if (FNexit(com_rx_byte)) adp_state <= STD_IOCHK; // exit + else if (FNvalid_EOL(com_rx_byte)) +`ifndef ADPBASIC + begin adp_count <= adp_param; adp_state <= ADP_ACTION; end // parameter complete on EOL +`else + begin adp_state <= ADP_ACTION; end // parameter complete on EOL +`endif + else + begin adp_param <= FNBuild_param32_hexdigit(adp_param, com_rx_byte); com_rx_ack <= 1; end // build parameter + end + else com_rx_ack <= 1; + + ADP_ACTION: // parse command and action with parameter + if (FNexit(com_rx_byte)) + adp_state <= STD_IOCHK; + else if (FNvalid_cmd(adp_cmd) == CMD_A) + begin if (adp_param == 32'hffffffff) adp_param <= adp_addr; else adp_addr <= adp_param; + adp_state <= ADP_ECHOCMD; end + else if (FNvalid_cmd(adp_cmd) == CMD_C) begin + if (adp_param[31:8] == 0) // report GPO + begin adp_state <= ADP_SYSCTL; end + else if (adp_param[31:8] == 1) // clear bits in GPO + begin adp_sys[7:0] <= adp_sys[7:0] & ~adp_param[7:0]; adp_state <= ADP_SYSCTL; end + else if (adp_param[31:8] == 2) // set bits in GPO + begin adp_sys[7:0] <= adp_sys[7:0] | adp_param[7:0]; adp_state <= ADP_SYSCTL; end + else if (adp_param[31:8] == 3) // overwrite bits in GPO + begin adp_sys[7:0] <= adp_param[7:0]; adp_state <= ADP_SYSCTL; end + else // 4 etc, report GPO + begin adp_state <= ADP_SYSCTL; end + end + else if (FNvalid_cmd(adp_cmd) == CMD_R) + begin ADP_BUSREADINC_next(); adp_state <= ADP_READ; end // no param + else if (FNvalid_cmd(adp_cmd) == CMD_S) + begin adp_state <= ADP_SYSCHK; end + else if (FNvalid_cmd(adp_cmd) == CMD_W) + begin adp_bus_data <= adp_param; ADP_BUSWRITEINC_next(); adp_state <= ADP_WRITE; end + else if (FNvalid_cmd(adp_cmd) == CMD_X) + begin com_tx_byte <= 8'h0a; com_tx_req <= 1; adp_state <= ADP_EXIT; end +`ifndef ADPBASIC + else if (FNvalid_cmd(adp_cmd) == CMD_B) + if (FNcount_down_zero_next(adp_param)) adp_state <= ADP_ECHOCMD; else adp_state <= ADP_BCTRL; // non-zero count + else if (FNvalid_cmd(adp_cmd) == CMD_M) + begin if (adp_param == 32'hffffffff) adp_param <= adp_mask; else adp_mask <= adp_param; + adp_state <= ADP_ECHOCMD; end + else if (FNvalid_cmd(adp_cmd) == CMD_P) + if (FNcount_down_zero_next(adp_param)) adp_state <= ADP_ECHOCMD; else adp_state <= ADP_POLL; // non-zero count + else if (FNvalid_cmd(adp_cmd) == CMD_V) + begin if (adp_param == 32'hffffffff) adp_param <= adp_val; else adp_val <= adp_param; + adp_state <= ADP_ECHOCMD; end + else if (FNvalid_cmd(adp_cmd) == CMD_Z) + if (FNcount_down_zero_next(adp_param)) adp_state <= ADP_ECHOCMD; else adp_state <= ADP_ZCTRL; // non-zero count +`endif + else + begin ADP_txchar_next("?"); adp_state <= ADP_UNKNOWN; end // unrecognised/invald + +// >>>>>>>>>>>>>>>> ADP BUS WRITE and READ >>>>>>>>>>>>>>>>>>>>>> + + ADP_WRITE: // perform bus write at current address pointer (and auto increment) + if (adp_bus_done) begin adp_state <= ADP_ECHOCMD; end + else begin ADP_BUSWRITEINC_next(); end // extend request + + ADP_READ: // perform bus read at current adp address (and auto increment) - and report in hex + if (adp_bus_done) begin adp_bus_data <= HRDATA32_i; ADP_txchar_next("R"); com_tx_req <= 1; adp_state <= ADP_ECHOCMDSP; end + else begin ADP_BUSREADINC_next(); end // extend request + +`ifndef ADPBASIC + +// >>>>>>>>>>>>>>>> ADP BINARY UPLOAD >>>>>>>>>>>>>>>>>>>>>> + ADP_BCTRL: // set control value + begin com_rx_ack <= 1; adp_state <= ADP_BREADB0; end // read next 4 bytes + ADP_BREADB0: // read raw binary byte + if (com_rx_done) begin com_rx_ack <= 1; adp_bus_data[31:24] <= com_rx_byte; adp_state <= ADP_BREADB1; end + else com_rx_ack <= 1; // extend stream request if not ready + ADP_BREADB1: // read raw binary byte + if (com_rx_done) begin com_rx_ack <= 1; adp_bus_data[23:16] <= com_rx_byte; adp_state <= ADP_BREADB2; end + else com_rx_ack <= 1; // extend stream request if not ready + ADP_BREADB2: // read raw binary byte 0 + if (com_rx_done) begin com_rx_ack <= 1; adp_bus_data[15: 8] <= com_rx_byte; adp_state <= ADP_BREADB3; end + else com_rx_ack <= 1; // extend stream request if not ready + ADP_BREADB3: // read raw binary byte 0 + if (com_rx_done) + begin adp_bus_data[ 7: 0] <= com_rx_byte; ADP_BUSWRITEINC_next(); adp_count_dec <= 1; adp_state <= ADP_BWRITE; end + else com_rx_ack <= 1; // extend stream request if not ready + ADP_BWRITE: // Write word to Addr++ + if (adp_bus_done) begin // auto address++, count-- + if (FNcount_down_zero_next(adp_count)) adp_state <= ADP_ECHOCMD; else begin adp_state <= ADP_BREADB0; end + end else begin ADP_BUSWRITEINC_next(); adp_count_dec <= 1; end // extend request + +// >>>>>>>>>>>>>>>> ADP BUS READ LOOP >>>>>>>>>>>>>>>>>>>>>> + ADP_POLL: // set poll value + begin adp_bus_req <= 1; adp_bus_write <= 0; adp_state <= ADP_POLL1; end + ADP_POLL1: // wait for read data, no addr++ + if (adp_bus_done) begin adp_bus_data <= HRDATA32_i; adp_count_dec <=1; adp_state <= ADP_POLL2; end + else begin adp_bus_req <= 1; adp_count_dec <=1; end + ADP_POLL2: + if (FNcount_down_zero_next(adp_count)) adp_state <= ADP_ECHOCMD; // timeout + else if (((adp_bus_data & adp_mask) ^ adp_val) == 0) adp_state <= ADP_WRITEHEX; // exact match + else adp_state <= ADP_POLL; + +// >>>>>>>>>>>>>>>> ADP ZERO MEMORY >>>>>>>>>>>>>>>>>>>>>> + ADP_ZCTRL: // set control value + begin adp_bus_data <= adp_val; ADP_BUSWRITEINC_next(); adp_count_dec <= 1; adp_state <= ADP_ZWRITE; end + ADP_ZWRITE: // Write word to Addr++ + if (adp_bus_done) begin // auto address++, count-- + if (FNcount_down_zero_next(adp_count)) adp_state <= ADP_ECHOCMD; else begin adp_state <= ADP_ZCTRL; end + end else begin ADP_BUSWRITEINC_next(); adp_count_dec <= 1; end // extend request +`endif + + // >>>>>>>>>>>>>>>> ADP MISC >>>>>>>>>>>>>>>>>>>>>> + + ADP_UNKNOWN: // output "?" + if (com_tx_done) begin ADP_LINEACK_next(); end + else com_tx_req <= 1; // extend stream request if not ready + + ADP_EXIT: // exit ADP mode + if (com_tx_done) adp_state <= STD_IOCHK; + else com_tx_req <= 1; // extend stream request if not ready + + ADP_SYSCHK: // check STDIN fifo + begin // no upper flags so STDIN char + if (std_tx_ack) begin std_tx_req <=1; std_tx_byte <= adp_param[7:0]; adp_state <= ADP_STDIN; end + else begin ADP_txchar_next(8'h0A); com_tx_req <= 1; adp_state <= ADP_LINEACK; end // newline and prompt + end + ADP_STDIN: // push char into STDIN + if (std_tx_done) begin adp_bus_data <= adp_param[7:0]; ADP_txchar_next("S"); com_tx_req <= 1; adp_state <= ADP_ECHOCMDSP; end + else std_tx_req <= 1; // extend + + ADP_SYSCTL: // read current status - and report in hex + begin adp_bus_data <= {GPI8_i[7:0],adp_sys[7:0],adp_param[15:0]}; ADP_txchar_next("C"); com_tx_req <= 1; adp_state <= ADP_ECHOCMDSP; end + + ADP_ECHOCMD: // output command and (param) data + begin adp_state <= ADP_ECHOCMDSP; ADP_txchar_next(adp_cmd & 8'h5f); adp_bus_data <= adp_param; end // output command char + ADP_ECHOCMDSP: // output command space and (bus) data + if (com_tx_done) begin adp_state <= ADP_WRITEHEXS; ADP_txchar_next(" "); end // output space char + else com_tx_req <= 1; // extend + + ADP_WRITEHEX: // output hex word with prefix + begin adp_state <= ADP_WRITEHEXS; ADP_txchar_next(" "); end // output "0" hex prefix + + ADP_WRITEHEXS: + if (com_tx_done) begin adp_state <= ADP_WRITEHEX9; ADP_txchar_next("0"); end // output "0" hex prefix + else com_tx_req <= 1; // extend + ADP_WRITEHEX9: + if (com_tx_done) begin adp_state <= ADP_WRITEHEX8; ADP_txchar_next("x"); end // output "x" hex prefix + else com_tx_req <= 1; // extend + ADP_WRITEHEX8: + if (com_tx_done) begin adp_state <= ADP_WRITEHEX7; ADP_hexdigit_next(adp_bus_data[31:28]); end // hex nibble 7 + else com_tx_req <= 1; // extend + ADP_WRITEHEX7: // output hex nibble 7 + if (com_tx_done) begin adp_state <= ADP_WRITEHEX6; ADP_hexdigit_next(adp_bus_data[27:24]); end // hex nibble 6 + else com_tx_req <= 1; // extend + ADP_WRITEHEX6: // output hex nibble 6 + if (com_tx_done) begin adp_state <= ADP_WRITEHEX5; ADP_hexdigit_next(adp_bus_data[23:20]); end // hex nibble 5 + else com_tx_req <= 1; // extend + ADP_WRITEHEX5: // output hex nibble 5 + if (com_tx_done) begin adp_state <= ADP_WRITEHEX4; ADP_hexdigit_next(adp_bus_data[19:16]); end // hex nibble 4 + else com_tx_req <= 1; // extend + ADP_WRITEHEX4: // output hex nibble 4 + if (com_tx_done) begin adp_state <= ADP_WRITEHEX3; ADP_hexdigit_next(adp_bus_data[15:12]); end // hex nibble 3 + else com_tx_req <= 1; // extend + ADP_WRITEHEX3: // output hex nibble 3 + if (com_tx_done) begin adp_state <= ADP_WRITEHEX2; ADP_hexdigit_next(adp_bus_data[11: 8]); end // hex nibble 2 + else com_tx_req <= 1; // extend + ADP_WRITEHEX2: // output hex nibble 2 + if (com_tx_done) begin adp_state <= ADP_WRITEHEX1; ADP_hexdigit_next(adp_bus_data[ 7: 4]); end // hex nibble 1 + else com_tx_req <= 1; // extend + ADP_WRITEHEX1: // output hex nibble 1 + if (com_tx_done) begin adp_state <= ADP_WRITEHEX0; ADP_hexdigit_next(adp_bus_data[ 3: 0]); end // hex nibble 0 + else com_tx_req <= 1; // extend + ADP_WRITEHEX0: // output hex nibble 0 (if not startup banner then scan to end of line before lineack + if (com_tx_done) begin + if (banner) begin ADP_LINEACK_next(); end + else begin ADP_txchar_next(8'h0A); com_tx_req <= 1; adp_state <= ADP_LINEACK; end // newline and prompt + end else com_tx_req <= 1; // extend + + ADP_LINEACK: // write EOLN + if (com_tx_done) begin + begin ADP_txchar_next(8'h0D); adp_state <= ADP_LINEACK2; end + end else com_tx_req <= 1; // extend + ADP_LINEACK2: // CR + if (com_tx_done) begin + if (banner) begin banner <= 0; adp_state <= STD_IOCHK; end + else begin ADP_txchar_next(PROMPT_CHAR); adp_state <= ADP_PROMPT; end + end else com_tx_req <= 1; // extend + default: + begin ADP_txchar_next("!"); adp_state <= ADP_UNKNOWN; end // default error + endcase + end + +endmodule + +////AHBLITE_ADPMASTER instancing +//ADPmaster +// #(.PROMPT_CHAR ("]")) +// ADPmaster( +// .HCLK (ahb_hclk ), +// .HRESETn (ahb_hrestn ), +// .HADDR32_o (ahb_haddr ), +// .HBURST3_o (ahb_hburst ), +// .HMASTLOCK_o (ahb_hmastlock ), +// .HPROT4_o (ahb_hprot ), +// .HSIZE3_o (ahb_hsize ), +// .HTRANS2_o (ahb_htrans ), +// .HWDATA32_o (ahb_hwdata ), +// .HWRITE_o (ahb_hwrite ), +// .HRDATA32_i (ahb_hrdata ), +// .HREADY_i (ahb_hready ), +// .HRESP_i (ahb_hresp ), + +// .COMRX_TREADY_o(com_rx_tready), +// .COMRX_TDATA_i(com_rx_tdata), +// .COMRX_TVALID_i(com_rx_tvalid), +// .STDRX_TREADY_o(std_rx_tready), +// .STDRX_TDATA_i(std_rx_tdata), +// .STDRX_TVALID_i(std_rx_tvalid), +// .COMTX_TVALID_o(com_tx_tvalid), +// .COMTX_TDATA_o(com_tx_tdata), +// .COMTX_TREADY_i(com_tx_tready), +// .STDTX_TVALID_o(std_tx_tvalid), +// .STDTX_TDATA_o(std_tx_tdata), +// .STDTX_TREADY_i(std_tx_tready) + +// ); diff --git a/IPLIB/FT1248_streamio_v1_0/ft1248_1bit_testbench.v b/IPLIB/FT1248_streamio_v1_0/ft1248_1bit_testbench.v new file mode 100644 index 0000000..f0b8b55 --- /dev/null +++ b/IPLIB/FT1248_streamio_v1_0/ft1248_1bit_testbench.v @@ -0,0 +1,285 @@ +module ft1248_streamio_v1_0 # + ( + // Users to add parameters here + // FTDI Interface 1,2,4 width supported + parameter integer FT1248_WIDTH = 1, + // FTDI clock always on - else quiet when no access + parameter integer FT1248_CLKON = 1 + + // User parameters ends + // Do not modify the parameters beyond this line + + // Parameters of Axi Stream Manager Bus Interface TXD + // Parameters of Axi Stream Subordinate Bus Interface RXD + ) + ( + // IO pad interface - to FT232R configured in 1/2/4/8 mode + output wire ft_clk_o, // SCLK + output wire ft_ssn_o, // SS_N + input wire ft_miso_i, // MISO + output wire [FT1248_WIDTH-1:0] ft_miosio_o, // MIOSIO tristate output when enabled + output wire [FT1248_WIDTH-1:0] ft_miosio_e, // MIOSIO tristate output enable (active hi) + output wire [FT1248_WIDTH-1:0] ft_miosio_z, // MIOSIO tristate output enable (active lo) + input wire [FT1248_WIDTH-1:0] ft_miosio_i, // MIOSIO tristate input + + input wire [7:0] ft_clkdiv, // divider prescaler to ensure SCLK <1MHz + + // User ports ends + // Do not modify the ports beyond this line + + // initially clocked from aclk + // asynch + input wire clk, + input wire resetn, + + // Ports of Axi Manager Bus Interface TXD + output wire txd_tvalid, + output wire [7 : 0] txd_tdata, + output wire txd_tlast, + input wire txd_tready, + + // Ports of Axi Subordinate Bus Interface RXD + output wire rxd_tready, + input wire [7 : 0] rxd_tdata, + input wire rxd_tlast, + input wire rxd_tvalid + ); + + //---------------------------------------------- + //-- State Machine encoding + //---------------------------------------------- + +// Explicit FSM state bit assignment +// bit [0] SCLK +// bit [1] MIO_OE +// bit [2] CMD/W +// bit [3] DAT/R +// bit [4] SSEL + +localparam FT_0_IDLE = 5'b00000; +localparam FT_1_IDLE = 5'b00001; +localparam FT_ZCMD_CLKLO = 5'b10100; +localparam FT_CMD_CLKHI = 5'b10111; +localparam FT_CMD_CLKLO = 5'b10110; +localparam FT_ZBT_CLKHI = 5'b10001; +localparam FT_ZBT_CLKLO = 5'b10000; +localparam FT_WD_CLKHI = 5'b11111; +localparam FT_WD_CLKLO = 5'b11110; +localparam FT_ZWD_CLKLO = 5'b11100; +localparam FT_RD_CLKHI = 5'b11001; +localparam FT_RD_CLKLO = 5'b11000; + +reg [4:0] ft_state; +// 9- bit shift register to support 8-bit data + 1 sequence control flag +// write data uses bits[7:0], with bit[8] set to flag length for serialized transfers +// read data uses bits[8:1], with bit[0] set to flag continuation for serialized transfers +reg [8:0] ft_reg; + + //---------------------------------------------- + //-- IO PAD control, parameterized on WIDTH param + //---------------------------------------------- + +wire bwid8 = (FT1248_WIDTH==8); +wire bwid4 = (FT1248_WIDTH==4); +wire bwid2 = (FT1248_WIDTH==2); +wire bwid1 = (FT1248_WIDTH==1); + +wire [7:0] ft_rdmasked; + +generate if (FT1248_WIDTH == 8) begin +assign ft_rdmasked[7:1] = ft_miosio_i[7:1]; +assign ft_miosio_o[7:1] = ft_reg[7:1]; +assign ft_miosio_e[7:1] = {7{ft_state[1]}}; +assign ft_miosio_z[7:1] = ~{7{ft_state[1]}}; +end +endgenerate + +generate if (FT1248_WIDTH == 4) begin +assign ft_rdmasked[7:1] = {4'b1111, ft_miosio_i[3:1]}; +assign ft_miosio_o[3:1] = ft_reg[3:1]; +assign ft_miosio_e[3:1] = {3{ft_state[1]}}; +assign ft_miosio_z[3:1] = ~{3{ft_state[1]}}; +end +endgenerate + +generate if (FT1248_WIDTH == 2) begin +assign ft_rdmasked[7:1] = {6'b111111, ft_miosio_i[1]}; +assign ft_miosio_o[1] = ft_reg[1]; +assign ft_miosio_e[1] = ft_state[1]; +assign ft_miosio_z[1] = !ft_state[1]; +end +endgenerate + +generate if (FT1248_WIDTH == 1) +assign ft_rdmasked[7:1] = 7'b1111111; +endgenerate + +assign ft_rdmasked[0] = ft_miosio_i[0]; +assign ft_miosio_o[0] = ft_reg[0]; +assign ft_miosio_e[0] = ft_state[1]; +assign ft_miosio_z[0] = !ft_state[1]; + +assign ft_clk_o = ft_state[0]; +assign ft_ssn_o = !ft_state[4]; + +// diagnostic decodes +//wire ft_cmd = !ft_state[3] & ft_state[2]; +//wire ft_dwr = ft_state[3] & ft_state[2]; +//wire ft_drd = ft_state[3] & !ft_state[2]; + + + //---------------------------------------------- + //-- Internal clock prescaler + //---------------------------------------------- + + // clock prescaler, ft_clken enables serial IO engine clocking + reg [7:0] ft_clkcnt_r; + reg ft_clken; + + always @(posedge clk or negedge resetn ) + begin + if (!resetn) begin + ft_clkcnt_r <= 0; + ft_clken <= 0; + end + else begin + ft_clken <= (ft_clkcnt_r == ft_clkdiv); + ft_clkcnt_r <= (ft_clkcnt_r == ft_clkdiv) ? 0 : (ft_clkcnt_r +1); + end + end + + //---------------------------------------------- + //-- Internal "synchronizers" (dual stage) + //---------------------------------------------- + // synchronizers for channel ready flags when idle + // (treat these signals as synchronous during transfer sequencing) + reg ft_miso_i_sync; + reg ft_miosio_i0_sync; + reg ft_miso_i_sync_1; + reg ft_miosio_i0_sync_1; + + always @(posedge clk or negedge resetn ) + begin + if (!resetn) begin + ft_miso_i_sync_1 <= 1; + ft_miosio_i0_sync_1 <= 1; + ft_miso_i_sync <= 1; + ft_miosio_i0_sync <= 1; + end + else begin + ft_miso_i_sync_1 <= ft_miso_i; + ft_miosio_i0_sync_1 <= ft_miosio_i[0]; + ft_miso_i_sync <= ft_miso_i_sync_1; + ft_miosio_i0_sync <= ft_miosio_i0_sync_1; + end + end + + //---------------------------------------------- + //-- AXI Stream interface handshakes + //---------------------------------------------- + +reg ft_txf; // FTDI Transmit channel Full +reg ft_rxe; // FTDO Receive channel Empty +reg ft_wcyc; // read access committed +reg ft_nak; // check for NAK terminate + +// TX stream delivers valid FT1248 read data transfer +// 8-bit write port with extra top-bit used as valid qualifer +reg [8:0] txdata; +assign txd_tdata = txdata[7:0]; +assign txd_tvalid = txdata[8]; + +// activate if RX channel data and the stream buffer is not full +wire ft_rxreq = !ft_rxe & !txdata[8]; + + +// RX stream handshakes on valid FT1248 write data transfer +reg rxdone; +reg rxrdy; +assign rxd_tready = rxdone; + +// activate if TX channel not full and and the stream buffer data valid +wire ft_txreq = !ft_txf & rxd_tvalid; // & !rxdone; // FTDI TX data ready and rxstream ready + +// FTDI1248 commands +wire [3:0] wcmd = 4'b0000; // write request +wire [3:0] rcmd = 4'b0001; // read request +wire [3:0] fcmd = 4'b0100; // write flush request +// and full FT1248 command bit patterns (using top-bits for shift sequencing) +wire [8:0] wcmdpatt = {2'b11, wcmd[0], wcmd[1], 1'b0, wcmd[2], 1'b0, 1'b0, wcmd[3]}; +wire [8:0] rcmdpatt = {2'b11, rcmd[0], rcmd[1], 1'b0, rcmd[2], 1'b0, 1'b0, rcmd[3]}; + + +// FTDI1248 state machine + +always @(posedge clk or negedge resetn) + if (!resetn) begin + ft_state <= FT_0_IDLE; + ft_reg <= 0; + txdata <= 0; + rxdone <= 0; + ft_wcyc <= 0; + ft_txf <= 1; // ftdi channel TXE# ('1' full) + ft_rxe <= 1; // ftdi channel RXF# ('1' empty) + ft_nak <= 0; + end + else begin + ft_txf <= (ft_state==FT_0_IDLE) ? ft_miosio_i0_sync : ft_txf & !( ft_wcyc &(ft_state==FT_ZBT_CLKHI) & ft_miso_i); + ft_rxe <= (ft_state==FT_0_IDLE) ? ft_miso_i_sync : ft_rxe & !(!ft_wcyc & (ft_state==FT_ZBT_CLKHI) & ft_miso_i); + txdata[8] <= txdata[8] & !txd_tready; // tx_valid handshake + rxdone <= (ft_clken & (ft_state==FT_ZWD_CLKLO) & !ft_nak); // | (rxdone & !rxd_tvalid); + if (ft_clken) + case (ft_state) + FT_0_IDLE: begin // RX req priority + if (ft_rxreq) begin ft_reg <= rcmdpatt; ft_state <= FT_ZCMD_CLKLO; end + else if (ft_txreq) begin ft_reg <= wcmdpatt; ft_state <= FT_ZCMD_CLKLO; ft_wcyc <= 1; end + else ft_state <= (FT1248_CLKON!=0)? FT_1_IDLE : FT_0_IDLE; + end + FT_1_IDLE: + ft_state <= FT_0_IDLE; + FT_ZCMD_CLKLO: + ft_state <= FT_CMD_CLKHI; + FT_CMD_CLKHI: + ft_state <= FT_CMD_CLKLO; + FT_CMD_CLKLO: // 2, 4 or 7 shifts + if (bwid8) begin ft_reg <= FT_ZBT_CLKHI; end + else if (bwid4) begin ft_reg <= {4'b0000,ft_reg[8:4]}; ft_state <= (|ft_reg[8:5]) ? FT_CMD_CLKHI : FT_ZBT_CLKHI; end + else if (bwid2) begin ft_reg <= { 2'b00,ft_reg[8:2]}; ft_state <= (|ft_reg[8:3]) ? FT_CMD_CLKHI : FT_ZBT_CLKHI; end + else begin ft_reg <= { 1'b0,ft_reg[8:1]}; ft_state <= (|ft_reg[8:3]) ? FT_CMD_CLKHI : FT_ZBT_CLKHI; end + FT_ZBT_CLKHI: + ft_state <= FT_ZBT_CLKLO; + FT_ZBT_CLKLO: + if (ft_wcyc) begin ft_reg <= {1'b1,rxd_tdata}; ft_state <= FT_WD_CLKHI; end + else begin ft_reg <= 9'b011111111; ft_state <= FT_RD_CLKHI; end + FT_WD_CLKHI: + if (ft_miso_i & ft_reg[8]) begin ft_nak <= 1'b1; ft_state <= FT_ZWD_CLKLO; end // NAK terminate on first cycle + else if (bwid8) ft_state <= (ft_reg[8]) ? FT_WD_CLKLO : FT_ZWD_CLKLO; // special case repeat on write data + else if (bwid4) ft_state <= (|ft_reg[8:5]) ? FT_WD_CLKLO : FT_ZWD_CLKLO; + else if (bwid2) ft_state <= (|ft_reg[8:3]) ? FT_WD_CLKLO : FT_ZWD_CLKLO; + else ft_state <= (|ft_reg[8:2]) ? FT_WD_CLKLO : FT_ZWD_CLKLO; + FT_WD_CLKLO: + if (bwid8) begin ft_reg <= { 1'b0,ft_reg[7:0]}; ft_state <= FT_WD_CLKHI; end // clear top flag + else if (bwid4) begin ft_reg <= {4'b0000,ft_reg[8:4]}; ft_state <= FT_WD_CLKHI; end // shift 4 bits right + else if (bwid2) begin ft_reg <= { 2'b00,ft_reg[8:2]}; ft_state <= FT_WD_CLKHI; end // shift 2 bits right + else begin ft_reg <= { 1'b0,ft_reg[8:1]}; ft_state <= FT_WD_CLKHI; end // shift 1 bit right + FT_ZWD_CLKLO: + if (ft_nak) begin ft_nak<= 1'b0; ft_state <= FT_0_IDLE; ft_wcyc <= 1'b0; end // terminate without TX handshake + else begin ft_state <= FT_0_IDLE; ft_wcyc <= 1'b0; end + FT_RD_CLKHI: // capture iodata pins end of CLKHI phase + if (ft_miso_i & (&ft_reg[7:0])) begin ft_nak <= 1'b1; ft_state <= FT_RD_CLKLO; end // NAK terminate on first cycle + else if (bwid8) begin ft_reg <= (ft_reg[0]) ? {ft_rdmasked[7:0],1'b1} : {ft_reg[8:1],1'b0}; ft_state <= FT_RD_CLKLO; end // 8-bit read twice + else if (bwid4) begin ft_reg <= {ft_rdmasked[3:0],ft_reg[8:4]}; ft_state <= FT_RD_CLKLO; end + else if (bwid2) begin ft_reg <= {ft_rdmasked[1:0],ft_reg[8:2]}; ft_state <= FT_RD_CLKLO; end + else begin ft_reg <= {ft_rdmasked[ 0],ft_reg[8:1]}; ft_state <= FT_RD_CLKLO; end + FT_RD_CLKLO: + if (ft_nak) begin ft_nak<= 1'b0; ft_state <= FT_0_IDLE; txdata <= 9'b0; end // terminate without TX handshake + else if (ft_reg[0]) begin ft_state <= FT_RD_CLKHI; ft_reg[0] <= !(bwid8); end // loop until all 8 bits shifted in (or 8-bit read repeated) + else begin ft_state <= FT_0_IDLE; txdata <= {1'b1,ft_reg[8:1]}; end + default: + ft_state <= FT_0_IDLE; + endcase + end + + // User logic ends + +endmodule diff --git a/IPLIB/FT1248_streamio_v1_0/ft1248_streamio_v1_0.v b/IPLIB/FT1248_streamio_v1_0/ft1248_streamio_v1_0.v new file mode 100755 index 0000000..b5b8d4b --- /dev/null +++ b/IPLIB/FT1248_streamio_v1_0/ft1248_streamio_v1_0.v @@ -0,0 +1,305 @@ +//----------------------------------------------------------------------------- +// soclabs on-chip AXI stream to FTDI FT1248 controller +// A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license. +// +// Contributors +// +// David Flynn (d.w.flynn@soton.ac.uk) +// +// Copyright © 2022, SoC Labs (www.soclabs.org) +//----------------------------------------------------------------------------- + +module ft1248_streamio_v1_0 # + ( + // Users to add parameters here + // FTDI Interface 1,2,4 width supported + parameter integer FT1248_WIDTH = 1, + // FTDI clock always on - else quiet when no access + parameter integer FT1248_CLKON = 1 + + // User parameters ends + // Do not modify the parameters beyond this line + + // Parameters of Axi Stream Master Bus Interface TXD + // Parameters of Axi Stream Slave Bus Interface RXD + ) + ( + // IO pad interface - to FT232R configured in 1/2/4/8 mode + output wire ft_clk_o, // SCLK + output wire ft_ssn_o, // SS_N + input wire ft_miso_i, // MISO + output wire [FT1248_WIDTH-1:0] ft_miosio_o, // MIOSIO tristate output when enabled + output wire [FT1248_WIDTH-1:0] ft_miosio_e, // MIOSIO tristate output enable (active hi) + output wire [FT1248_WIDTH-1:0] ft_miosio_z, // MIOSIO tristate output enable (active lo) + input wire [FT1248_WIDTH-1:0] ft_miosio_i, // MIOSIO tristate input + + input wire [7:0] ft_clkdiv, // divider prescaler to ensure SCLK <1MHz + + // User ports ends + // Do not modify the ports beyond this line + + // initially clocked from aclk + // asynch + input wire clk, + input wire resetn, + + // Ports of Axi Master Bus Interface TXD + output wire txd_tvalid, + output wire [7 : 0] txd_tdata, + output wire txd_tlast, + input wire txd_tready, + + // Ports of Axi Slave Bus Interface RXD + output wire rxd_tready, + input wire [7 : 0] rxd_tdata, + input wire rxd_tlast, + input wire rxd_tvalid + ); + + //---------------------------------------------- + //-- State Machine encoding + //---------------------------------------------- + +// Explicit FSM state bit assignment +// bit [0] SCLK +// bit [1] MIO_OE +// bit [2] CMD/W +// bit [3] DAT/R +// bit [4] SSEL + +localparam FT_0_IDLE = 5'b00000; +localparam FT_1_IDLE = 5'b00001; +localparam FT_ZCMD_CLKLO = 5'b10100; +localparam FT_CMD_CLKHI = 5'b10111; +localparam FT_CMD_CLKLO = 5'b10110; +localparam FT_ZBT_CLKHI = 5'b10001; +localparam FT_ZBT_CLKLO = 5'b10000; +localparam FT_WD_CLKHI = 5'b11111; +localparam FT_WD_CLKLO = 5'b11110; +localparam FT_ZWD_CLKLO = 5'b11100; +localparam FT_RD_CLKHI = 5'b11001; +localparam FT_RD_CLKLO = 5'b11000; + +reg [4:0] ft_state; +// 9- bit shift register to support 8-bit data + 1 sequence control flag +// write data uses bits[7:0], with bit[8] set to flag length for serialized transfers +// read data uses bits[8:1], with bit[0] set to flag continuation for serialized transfers +reg [8:0] ft_reg; + + //---------------------------------------------- + //-- IO PAD control, parameterized on WIDTH param + //---------------------------------------------- + +wire bwid8 = (FT1248_WIDTH==8); +wire bwid4 = (FT1248_WIDTH==4); +wire bwid2 = (FT1248_WIDTH==2); +wire bwid1 = (FT1248_WIDTH==1); + +wire [7:0] ft_rdmasked; + +generate if (FT1248_WIDTH == 8) begin +assign ft_rdmasked[7:1] = ft_miosio_i[7:1]; +assign ft_miosio_o[7:1] = ft_reg[7:1]; +assign ft_miosio_e[7:1] = {7{ft_state[1]}}; +assign ft_miosio_z[7:1] = ~{7{ft_state[1]}}; +end +endgenerate + +generate if (FT1248_WIDTH == 4) begin +assign ft_rdmasked[7:1] = {4'b1111, ft_miosio_i[3:1]}; +assign ft_miosio_o[3:1] = ft_reg[3:1]; +assign ft_miosio_e[3:1] = {3{ft_state[1]}}; +assign ft_miosio_z[3:1] = ~{3{ft_state[1]}}; +end +endgenerate + +generate if (FT1248_WIDTH == 2) begin +assign ft_rdmasked[7:1] = {6'b111111, ft_miosio_i[1]}; +assign ft_miosio_o[1] = ft_reg[1]; +assign ft_miosio_e[1] = ft_state[1]; +assign ft_miosio_z[1] = ~ft_state[1]; +end +endgenerate + +generate if (FT1248_WIDTH == 1) +assign ft_rdmasked[7:1] = 7'b1111111; +endgenerate + +assign ft_rdmasked[0] = ft_miosio_i[0]; +assign ft_miosio_o[0] = ft_reg[0]; +assign ft_miosio_e[0] = ft_state[1]; +assign ft_miosio_z[0] = ~ft_state[1]; + +assign ft_clk_o = ft_state[0]; +assign ft_ssn_o = !ft_state[4]; + +// diagnostic decodes +//wire ft_cmd = !ft_state[3] & ft_state[2]; +//wire ft_dwr = ft_state[3] & ft_state[2]; +//wire ft_drd = ft_state[3] & !ft_state[2]; + + + //---------------------------------------------- + //-- Internal clock prescaler + //---------------------------------------------- + + // clock prescaler, ft_clken enables serial IO engine clocking + reg [7:0] ft_clkcnt_r; + reg ft_clken; + + always @(posedge clk or negedge resetn ) + begin + if (!resetn) begin + ft_clkcnt_r <= 0; + ft_clken <= 0; + end + else begin + ft_clken <= (ft_clkcnt_r == ft_clkdiv); + ft_clkcnt_r <= (ft_clkcnt_r == ft_clkdiv) ? 0 : (ft_clkcnt_r +1); + end + end + + //---------------------------------------------- + //-- Internal "synchronizers" (dual stage) + //---------------------------------------------- + // synchronizers for channel ready flags when idle + // (treat these signals as synchronous during transfer sequencing) + reg ft_miso_i_sync; + reg ft_miosio_i0_sync; + reg ft_miso_i_sync_1; + reg ft_miosio_i0_sync_1; + + always @(posedge clk or negedge resetn ) + begin + if (!resetn) begin + ft_miso_i_sync_1 <= 1; + ft_miosio_i0_sync_1 <= 1; + ft_miso_i_sync <= 1; + ft_miosio_i0_sync <= 1; + end + else begin + ft_miso_i_sync_1 <= ft_miso_i; + ft_miosio_i0_sync_1 <= ft_miosio_i[0]; + ft_miso_i_sync <= ft_miso_i_sync_1; + ft_miosio_i0_sync <= ft_miosio_i0_sync_1; + end + end + + //---------------------------------------------- + //-- AXI Stream interface handshakes + //---------------------------------------------- + +reg ft_txf; // FTDI Transmit channel Full +reg ft_rxe; // FTDO Receive channel Empty +reg ft_wcyc; // read access committed +reg ft_nak; // check for NAK terminate + +// TX stream delivers valid FT1248 read data transfer +// 8-bit write port with extra top-bit used as valid qualifer +reg [8:0] txdata; +assign txd_tdata = txdata[7:0]; +assign txd_tvalid = txdata[8]; + +// activate if RX channel data and the stream buffer is not full +wire ft_rxreq = !ft_rxe & !txdata[8]; + + +// RX stream handshakes on valid FT1248 write data transfer +reg rxdone; +reg rxrdy; +assign rxd_tready = rxdone; + +// activate if TX channel not full and and the stream buffer data valid +wire ft_txreq = !ft_txf & rxd_tvalid; // & !rxdone; // FTDI TX data ready and rxstream ready + +// FTDI1248 commands +wire [3:0] wcmd = 4'b0000; // write request +wire [3:0] rcmd = 4'b0001; // read request +wire [3:0] fcmd = 4'b0100; // write flush request +//wire [3:0] rcmd = 4'b1000; // read request BE bit-pattern +//wire [3:0] fcmd = 4'b0010; // write flush request BE bit-pattern +// and full FT1248 command bit patterns (using top-bits for shift sequencing) +wire [8:0] wcmdpatt = {2'b11, wcmd[0], wcmd[1], 1'b0, wcmd[2], 1'b0, 1'b0, wcmd[3]}; +wire [8:0] rcmdpatt = {2'b11, rcmd[0], rcmd[1], 1'b0, rcmd[2], 1'b0, 1'b0, rcmd[3]}; + +reg ssn_del; +always @(posedge clk or negedge resetn) + if (!resetn) + ssn_del <= 1'b1; + else if (ft_clken) + ssn_del <= ft_ssn_o; +wire ssn_start = ft_ssn_o & ssn_del; + +// FTDI1248 state machine + +always @(posedge clk or negedge resetn) + if (!resetn) begin + ft_state <= FT_0_IDLE; + ft_reg <= 0; + txdata <= 0; + rxdone <= 0; + ft_wcyc <= 0; + ft_txf <= 1; // ftdi channel TXE# ('1' full) + ft_rxe <= 1; // ftdi channel RXF# ('1' empty) + ft_nak <= 0; + end + else begin + ft_txf <= (ft_state==FT_0_IDLE) ? (ft_miosio_i[0] | ft_miosio_i0_sync) : 1'b1; //ft_txf & !( ft_wcyc &(ft_state==FT_ZBT_CLKHI) & ft_miso_i); + ft_rxe <= (ft_state==FT_0_IDLE) ? (ft_miso_i | ft_miso_i_sync) : 1'b1; //ft_rxe & !(!ft_wcyc & (ft_state==FT_ZBT_CLKHI) & ft_miso_i); + txdata[8] <= txdata[8] & !txd_tready; // tx_valid handshake + rxdone <= (ft_clken & (ft_state==FT_ZWD_CLKLO) & !ft_nak) | (rxdone & !rxd_tvalid); // hold until acknowledged + if (ft_clken) + case (ft_state) + FT_0_IDLE: begin // RX req priority + if (ssn_start & ft_rxreq) begin ft_reg <= rcmdpatt; ft_state <= FT_ZCMD_CLKLO; end + else if (ssn_start & ft_txreq) begin ft_reg <= wcmdpatt; ft_state <= FT_ZCMD_CLKLO; ft_wcyc <= 1; end + else ft_state <= (!ft_txf | !ft_rxe | (FT1248_CLKON!=0)) ? FT_1_IDLE : FT_0_IDLE; + end + FT_1_IDLE: + ft_state <= FT_0_IDLE; + FT_ZCMD_CLKLO: + ft_state <= FT_CMD_CLKHI; + FT_CMD_CLKHI: + ft_state <= FT_CMD_CLKLO; + FT_CMD_CLKLO: // 2, 4 or 7 shifts + if (bwid8) begin ft_reg <= FT_ZBT_CLKHI; end + else if (bwid4) begin ft_reg <= {4'b0000,ft_reg[8:4]}; ft_state <= (|ft_reg[8:5]) ? FT_CMD_CLKHI : FT_ZBT_CLKHI; end + else if (bwid2) begin ft_reg <= { 2'b00,ft_reg[8:2]}; ft_state <= (|ft_reg[8:3]) ? FT_CMD_CLKHI : FT_ZBT_CLKHI; end + else begin ft_reg <= { 1'b0,ft_reg[8:1]}; ft_state <= (|ft_reg[8:3]) ? FT_CMD_CLKHI : FT_ZBT_CLKHI; end + FT_ZBT_CLKHI: + ft_state <= FT_ZBT_CLKLO; + FT_ZBT_CLKLO: + if (ft_wcyc) begin ft_reg <= {1'b1,rxd_tdata}; ft_state <= FT_WD_CLKHI; end + else begin ft_reg <= 9'b011111111; ft_state <= FT_RD_CLKHI; end + FT_WD_CLKHI: + if (ft_miso_i & ft_reg[8]) begin ft_nak <= 1'b1; ft_state <= FT_ZWD_CLKLO; end // NAK terminate on first cycle + else if (bwid8) ft_state <= (ft_reg[8]) ? FT_WD_CLKLO : FT_ZWD_CLKLO; // special case repeat on write data + else if (bwid4) ft_state <= (|ft_reg[8:5]) ? FT_WD_CLKLO : FT_ZWD_CLKLO; + else if (bwid2) ft_state <= (|ft_reg[8:3]) ? FT_WD_CLKLO : FT_ZWD_CLKLO; + else ft_state <= (|ft_reg[8:2]) ? FT_WD_CLKLO : FT_ZWD_CLKLO; + FT_WD_CLKLO: + if (bwid8) begin ft_reg <= { 1'b0,ft_reg[7:0]}; ft_state <= FT_WD_CLKHI; end // clear top flag + else if (bwid4) begin ft_reg <= {4'b0000,ft_reg[8:4]}; ft_state <= FT_WD_CLKHI; end // shift 4 bits right + else if (bwid2) begin ft_reg <= { 2'b00,ft_reg[8:2]}; ft_state <= FT_WD_CLKHI; end // shift 2 bits right + else begin ft_reg <= { 1'b0,ft_reg[8:1]}; ft_state <= FT_WD_CLKHI; end // shift 1 bit right + FT_ZWD_CLKLO: + if (ft_nak) begin ft_nak<= 1'b0; ft_state <= FT_0_IDLE; ft_wcyc <= 1'b0; end // terminate without TX handshake + else begin ft_state <= FT_0_IDLE; ft_wcyc <= 1'b0; end + FT_RD_CLKHI: // capture iodata pins end of CLKHI phase + if (ft_miso_i & (&ft_reg[7:0])) begin ft_nak <= 1'b1; ft_state <= FT_RD_CLKLO; end // NAK terminate on first cycle + else if (bwid8) begin ft_reg <= (ft_reg[0]) ? {ft_rdmasked[7:0],1'b1} : {ft_reg[8:1],1'b0}; ft_state <= FT_RD_CLKLO; end // 8-bit read twice + else if (bwid4) begin ft_reg <= {ft_rdmasked[3:0],ft_reg[8:4]}; ft_state <= FT_RD_CLKLO; end + else if (bwid2) begin ft_reg <= {ft_rdmasked[1:0],ft_reg[8:2]}; ft_state <= FT_RD_CLKLO; end + else begin ft_reg <= {ft_rdmasked[ 0],ft_reg[8:1]}; ft_state <= FT_RD_CLKLO; end + FT_RD_CLKLO: + if (ft_nak) begin ft_nak<= 1'b0; ft_state <= FT_0_IDLE; txdata <= 9'b0; end // terminate without TX handshake + else if (ft_reg[0]) begin ft_state <= FT_RD_CLKHI; ft_reg[0] <= !(bwid8); end // loop until all 8 bits shifted in (or 8-bit read repeated) + else begin ft_state <= FT_0_IDLE; txdata <= {1'b1,ft_reg[8:1]}; end + default: + ft_state <= FT_0_IDLE; + endcase + end + + // User logic ends + +endmodule diff --git a/IPLIB/axi_stream_io_v1_0/axi_stream_io_v1_0.v b/IPLIB/axi_stream_io_v1_0/axi_stream_io_v1_0.v new file mode 100755 index 0000000..a229917 --- /dev/null +++ b/IPLIB/axi_stream_io_v1_0/axi_stream_io_v1_0.v @@ -0,0 +1,114 @@ + +`timescale 1 ns / 1 ps + + module iostream_v1_0 # + ( + // Users to add parameters here + + // User parameters ends + // Do not modify the parameters beyond this line + + + // Parameters of Axi Slave Bus Interface axi + parameter integer C_axi_DATA_WIDTH = 32, + parameter integer C_axi_ADDR_WIDTH = 4, + + // Parameters of Axi Master Bus Interface tx + parameter integer C_tx_TDATA_WIDTH = 8, + parameter integer C_tx_START_COUNT = 3, + + // Parameters of Axi Slave Bus Interface rx + parameter integer C_rx_TDATA_WIDTH = 8 + ) + ( + // Users to add ports here + + // User ports ends + // Do not modify the ports beyond this line + + + // Ports of Axi Slave Bus Interface axi + input wire axi_aclk, + input wire axi_aresetn, + input wire [C_axi_ADDR_WIDTH-1 : 0] axi_awaddr, + input wire [2 : 0] axi_awprot, + input wire axi_awvalid, + output wire axi_awready, + input wire [C_axi_DATA_WIDTH-1 : 0] axi_wdata, + input wire [(C_axi_DATA_WIDTH/8)-1 : 0] axi_wstrb, + input wire axi_wvalid, + output wire axi_wready, + output wire [1 : 0] axi_bresp, + output wire axi_bvalid, + input wire axi_bready, + input wire [C_axi_ADDR_WIDTH-1 : 0] axi_araddr, + input wire [2 : 0] axi_arprot, + input wire axi_arvalid, + output wire axi_arready, + output wire [C_axi_DATA_WIDTH-1 : 0] axi_rdata, + output wire [1 : 0] axi_rresp, + output wire axi_rvalid, + input wire axi_rready, + + output wire interrupt, + // Ports of Axi Master Bus Interface tx + output wire tx_tvalid, + output wire [C_tx_TDATA_WIDTH-1 : 0] tx_tdata, + output wire [(C_tx_TDATA_WIDTH/8)-1 : 0] tx_tstrb, + output wire tx_tlast, + input wire tx_tready, + + // Ports of Axi Slave Bus Interface rx + output wire rx_tready, + input wire [C_rx_TDATA_WIDTH-1 : 0] rx_tdata, + input wire [(C_rx_TDATA_WIDTH/8)-1 : 0] rx_tstrb, + input wire rx_tlast, + input wire rx_tvalid + ); +// Instantiation of Axi Bus Interface axi + iostream_v1_0_axi # ( + .C_S_AXI_DATA_WIDTH(C_axi_DATA_WIDTH), + .C_S_AXI_ADDR_WIDTH(C_axi_ADDR_WIDTH) + ) iostream_v1_0_axi_inst ( + .S_AXI_ACLK(axi_aclk), + .S_AXI_ARESETN(axi_aresetn), + .tx_tvalid(tx_tvalid), + .tx_tdata(tx_tdata), +// output wire [0 : 0] tx_tstrb, +// output wire tx_tlast, + .tx_tready(tx_tready), + .rx_tvalid(rx_tvalid), + .rx_tdata(rx_tdata), +// input wire [0 : 0] tx_tstrb, +// input wire tx_tlast, + .tx_tready(rx_tready), + .interrupt(interrupt), + .S_AXI_AWADDR(axi_awaddr), + .S_AXI_AWPROT(axi_awprot), + .S_AXI_AWVALID(axi_awvalid), + .S_AXI_AWREADY(axi_awready), + .S_AXI_WDATA(axi_wdata), + .S_AXI_WSTRB(axi_wstrb), + .S_AXI_WVALID(axi_wvalid), + .S_AXI_WREADY(axi_wready), + .S_AXI_BRESP(axi_bresp), + .S_AXI_BVALID(axi_bvalid), + .S_AXI_BREADY(axi_bready), + .S_AXI_ARADDR(axi_araddr), + .S_AXI_ARPROT(axi_arprot), + .S_AXI_ARVALID(axi_arvalid), + .S_AXI_ARREADY(axi_arready), + .S_AXI_RDATA(axi_rdata), + .S_AXI_RRESP(axi_rresp), + .S_AXI_RVALID(axi_rvalid), + .S_AXI_RREADY(axi_rready) + ); + +assign tx_tstrb[0:0] = tx_tvalid; +assign tx_tlast = 1'b0; + + // Add user logic here + + // User logic ends + + endmodule diff --git a/IPLIB/axi_stream_io_v1_0/axi_stream_io_v1_0_axi_s.v b/IPLIB/axi_stream_io_v1_0/axi_stream_io_v1_0_axi_s.v new file mode 100755 index 0000000..d8e6eea --- /dev/null +++ b/IPLIB/axi_stream_io_v1_0/axi_stream_io_v1_0_axi_s.v @@ -0,0 +1,424 @@ + +`timescale 1 ns / 1 ps + + module iostream_v1_0_axi # + ( + // Users to add parameters here + + // User parameters ends + // Do not modify the parameters beyond this line + + // Width of S_AXI data bus + parameter integer C_S_AXI_DATA_WIDTH = 32, + // Width of S_AXI address bus + parameter integer C_S_AXI_ADDR_WIDTH = 4 + ) + ( + // Users to add ports here + output wire interrupt, + + // Ports of Axi Master Bus Interface tx +// input wire tx_aclk, +// input wire tx_aresetn, + output wire tx_tvalid, + output wire [7 : 0] tx_tdata, +// output wire [0 : 0] tx_tstrb, +// output wire tx_tlast, + input wire tx_tready, + + // Ports of Axi Slave Bus Interface rx +// input wire rx_aclk, +// input wire rx_aresetn, + output wire rx_tready, + input wire [7 : 0] rx_tdata, +// input wire [0 : 0] rx_tstrb, +// input wire rx_tlast, + input wire rx_tvalid, + + // User ports ends + // Do not modify the ports beyond this line + + // Global Clock Signal + input wire S_AXI_ACLK, + // Global Reset Signal. This Signal is Active LOW + input wire S_AXI_ARESETN, + // Write address (issued by master, acceped by Slave) + input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR, + // Write channel Protection type. This signal indicates the + // privilege and security level of the transaction, and whether + // the transaction is a data access or an instruction access. + input wire [2 : 0] S_AXI_AWPROT, + // Write address valid. This signal indicates that the master signaling + // valid write address and control information. + input wire S_AXI_AWVALID, + // Write address ready. This signal indicates that the slave is ready + // to accept an address and associated control signals. + output wire S_AXI_AWREADY, + // Write data (issued by master, acceped by Slave) + input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA, + // Write strobes. This signal indicates which byte lanes hold + // valid data. There is one write strobe bit for each eight + // bits of the write data bus. + input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB, + // Write valid. This signal indicates that valid write + // data and strobes are available. + input wire S_AXI_WVALID, + // Write ready. This signal indicates that the slave + // can accept the write data. + output wire S_AXI_WREADY, + // Write response. This signal indicates the status + // of the write transaction. + output wire [1 : 0] S_AXI_BRESP, + // Write response valid. This signal indicates that the channel + // is signaling a valid write response. + output wire S_AXI_BVALID, + // Response ready. This signal indicates that the master + // can accept a write response. + input wire S_AXI_BREADY, + // Read address (issued by master, acceped by Slave) + input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR, + // Protection type. This signal indicates the privilege + // and security level of the transaction, and whether the + // transaction is a data access or an instruction access. + input wire [2 : 0] S_AXI_ARPROT, + // Read address valid. This signal indicates that the channel + // is signaling valid read address and control information. + input wire S_AXI_ARVALID, + // Read address ready. This signal indicates that the slave is + // ready to accept an address and associated control signals. + output wire S_AXI_ARREADY, + // Read data (issued by slave) + output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA, + // Read response. This signal indicates the status of the + // read transfer. + output wire [1 : 0] S_AXI_RRESP, + // Read valid. This signal indicates that the channel is + // signaling the required read data. + output wire S_AXI_RVALID, + // Read ready. This signal indicates that the master can + // accept the read data and response information. + input wire S_AXI_RREADY + ); + + // AXI4LITE signals + reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_awaddr; + reg axi_awready; + reg axi_wready; + reg [1 : 0] axi_bresp; + reg axi_bvalid; + reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_araddr; + reg axi_arready; + reg [C_S_AXI_DATA_WIDTH-1 : 0] axi_rdata; + reg [1 : 0] axi_rresp; + reg axi_rvalid; + + // Example-specific design signals + // local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH + // ADDR_LSB is used for addressing 32/64 bit registers/memories + // ADDR_LSB = 2 for 32 bits (n downto 2) + // ADDR_LSB = 3 for 64 bits (n downto 3) + localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32) + 1; + localparam integer OPT_MEM_ADDR_BITS = 1; + + //---------------------------------------------- + //-- Signals for user logic register space example + //------------------------------------------------ + //-- Number of Slave Registers 4 + reg [8:0] tx_reg; // TX data + reg [8:0] rx_reg; // RX data + reg [7:0] ctrl_reg; // ctrl + wire slv_reg_rden; + wire slv_reg_wren; + reg [7:0] reg_data_out; + integer byte_index; + reg aw_en; + + wire tx_req = tx_reg[8]; // request to transmit + wire tx_ack = tx_tready; // acknowledge when stream ready + wire tx_rdy = !tx_reg[8]; + wire rx_req = rx_tvalid; // request to receive + wire rx_ack = !rx_reg[8]; + wire rx_rdy = rx_reg[8]; + + //assign rx_reg[7:0] <= rx_tdata; + + // I/O Connections assignments + + assign interrupt = ctrl_reg[4] & (!tx_req | rx_req); + + // TX stream interface + assign tx_tdata = tx_reg[7:0]; + assign tx_tvalid = tx_req; + + // RX stream interface + assign rx_tready = rx_ack; + + //AXI Slave + assign S_AXI_AWREADY = axi_awready; + assign S_AXI_WREADY = axi_wready; + assign S_AXI_BRESP = axi_bresp; + assign S_AXI_BVALID = axi_bvalid; + assign S_AXI_ARREADY = axi_arready; + assign S_AXI_RDATA = axi_rdata; + assign S_AXI_RRESP = axi_rresp; + assign S_AXI_RVALID = axi_rvalid; + // Implement axi_awready generation + // axi_awready is asserted for one S_AXI_ACLK clock cycle when both + // S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_awready is + // de-asserted when reset is low. + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_awready <= 1'b0; + aw_en <= 1'b1; + end + else + begin + if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en) + begin + // slave is ready to accept write address when + // there is a valid write address and write data + // on the write address and data bus. This design + // expects no outstanding transactions. + axi_awready <= 1'b1; + aw_en <= 1'b0; + end + else if (S_AXI_BREADY && axi_bvalid) + begin + aw_en <= 1'b1; + axi_awready <= 1'b0; + end + else + begin + axi_awready <= 1'b0; + end + end + end + + // Implement axi_awaddr latching + // This process is used to latch the address when both + // S_AXI_AWVALID and S_AXI_WVALID are valid. + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_awaddr <= 0; + end + else + begin + if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en) + begin + // Write Address latching + axi_awaddr <= S_AXI_AWADDR; + end + end + end + + // Implement axi_wready generation + // axi_wready is asserted for one S_AXI_ACLK clock cycle when both + // S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is + // de-asserted when reset is low. + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_wready <= 1'b0; + end + else + begin + if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID && aw_en ) + begin + // slave is ready to accept write data when + // there is a valid write address and write data + // on the write address and data bus. This design + // expects no outstanding transactions. + axi_wready <= 1'b1; + end + else + begin + axi_wready <= 1'b0; + end + end + end + + // Implement memory mapped register select and write logic generation + // The write data is accepted and written to memory mapped registers when + // axi_awready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. Write strobes are used to + // select byte enables of slave registers while writing. + // These registers are cleared when reset (active low) is applied. + // Slave register write enable is asserted when valid address and data are available + // and the slave is ready to accept the write address and write data. + assign slv_reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID; + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + rx_reg <= 0; + else if ((ctrl_reg[1] == 1'b1)) + rx_reg <= 0; + else if (slv_reg_wren && (axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] == 2'h0)) + rx_reg[8:0] <= {1'b1, S_AXI_WDATA[7:0]}; + else if (slv_reg_rden && (axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] == 2'h0)) + rx_reg[8] <= 1'b0; + else if (rx_req & rx_ack) // check precedence (rx_req) + rx_reg[8:0] <= {1'b1, rx_tdata[7:0]}; + end + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + tx_reg <= 0; + else if ((ctrl_reg[0] == 1'b1)) + tx_reg <= 0; + else if (slv_reg_wren && (axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] == 2'h1)) + tx_reg[8:0] <= {1'b1, S_AXI_WDATA[7:0]}; + else if (tx_req & tx_ack) + tx_reg[8] <= 1'b0; + end + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + ctrl_reg <= 8'b00000100; + else if (slv_reg_wren && (axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] == 2'h3)) + ctrl_reg[7:0] <= S_AXI_WDATA[7:0]; + end + + // Implement write response logic generation + // The write response and response valid signals are asserted by the slave + // when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. + // This marks the acceptance of address and indicates the status of + // write transaction. + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_bvalid <= 0; + axi_bresp <= 2'b0; + end + else + begin + if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID) + begin + // indicates a valid write response is available + axi_bvalid <= 1'b1; + axi_bresp <= 2'b0; // 'OKAY' response + end // work error responses in future + else + begin + if (S_AXI_BREADY && axi_bvalid) + //check if bready is asserted while bvalid is high) + //(there is a possibility that bready is always asserted high) + begin + axi_bvalid <= 1'b0; + end + end + end + end + + // Implement axi_arready generation + // axi_arready is asserted for one S_AXI_ACLK clock cycle when + // S_AXI_ARVALID is asserted. axi_awready is + // de-asserted when reset (active low) is asserted. + // The read address is also latched when S_AXI_ARVALID is + // asserted. axi_araddr is reset to zero on reset assertion. + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_arready <= 1'b0; + axi_araddr <= 32'b0; + end + else + begin + if (~axi_arready && S_AXI_ARVALID) + begin + // indicates that the slave has acceped the valid read address + axi_arready <= 1'b1; + // Read address latching + axi_araddr <= S_AXI_ARADDR; + end + else + begin + axi_arready <= 1'b0; + end + end + end + + // Implement axi_arvalid generation + // axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both + // S_AXI_ARVALID and axi_arready are asserted. The slave registers + // data are available on the axi_rdata bus at this instance. The + // assertion of axi_rvalid marks the validity of read data on the + // bus and axi_rresp indicates the status of read transaction.axi_rvalid + // is deasserted on reset (active low). axi_rresp and axi_rdata are + // cleared to zero on reset (active low). + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_rvalid <= 0; + axi_rresp <= 0; + end + else + begin + if (axi_arready && S_AXI_ARVALID && ~axi_rvalid) + begin + // Valid read data is available at the read data bus + axi_rvalid <= 1'b1; + axi_rresp <= 2'b0; // 'OKAY' response + end + else if (axi_rvalid && S_AXI_RREADY) + begin + // Read data is accepted by the master + axi_rvalid <= 1'b0; + end + end + end + + // Implement memory mapped register select and read logic generation + // Slave register read enable is asserted when valid address is available + // and the slave is ready to accept the read address. + assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid; + always @(*) + begin + // Address decoding for reading registers + case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] ) + 2'h0 : reg_data_out <= rx_reg[7:0]; + 2'h1 : reg_data_out <= tx_reg[7:0]; + 2'h2 : reg_data_out <= {3'b000, ctrl_reg[4], !tx_rdy, tx_rdy, rx_rdy, rx_rdy}; + 2'h3 : reg_data_out <= ctrl_reg; + default : reg_data_out <= 0; + endcase + end + + // Output register or memory read data + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_rdata <= 0; + end + else + begin + // When there is a valid read address (S_AXI_ARVALID) with + // acceptance of read address by the slave (axi_arready), + // output the read dada + if (slv_reg_rden) + begin + axi_rdata <= {24'h000000, reg_data_out}; // register read data + end + end + end + + // Add user logic here + + // User logic ends + + endmodule -- GitLab