--- /dev/null
+/* ****************************************************************************\r
+-- (C) Copyright 2015 Kevin M. Hubbard @ Black Mesa Labs\r
+-- Source file: mesa2lb.v \r
+-- Date: October 4, 2015 \r
+-- Author: khubbard\r
+-- Language: Verilog-2001 \r
+-- Description: The Mesa Bus to LocalBus translator. Uses a Subslot for LB\r
+-- Reads and Writes using 4 different command nibbles. Also\r
+-- decodes the BSP subslots for things like pin control, power\r
+-- modes and scope out debug features.\r
+-- License: This project is licensed with the CERN Open Hardware Licence\r
+-- v1.2. You may redistribute and modify this project under the\r
+-- terms of the CERN OHL v.1.2. (http://ohwr.org/cernohl).\r
+-- This project is distributed WITHOUT ANY EXPRESS OR IMPLIED\r
+-- WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY QUALITY\r
+-- AND FITNESS FOR A PARTICULAR PURPOSE. Please see the CERN OHL\r
+-- v.1.2 for applicable Conditions.\r
+--\r
+--\r
+-- "\n"..."FFFF"."(F0-12-34-04)[11223344]\n" : \r
+-- 0xFF = Bus Idle ( NULLs )\r
+-- B0 0xF0 = New Bus Cycle to begin ( Nibble and bit orientation )\r
+-- B1 0x12 = Slot Number, 0xFF = Broadcast all slots, 0xFE = NULL Dest\r
+-- B2 0x3 = Sub-Slot within the chip (0-0xF)\r
+-- 0x4 = Command Nibble for Sub-Slot\r
+-- B3 0x04 = Number of Payload Bytes (0-255)\r
+-- 0x11223344 = Payload\r
+--\r
+-- Slot 0xFF = Broadcast all slots\r
+-- Sub-Slot 0x0 = User Local Bus Access\r
+-- Sub-Slot 0xE = PROM Local Bus Access\r
+-- 0x0 = Bus Write\r
+-- 0x1 = Bus Read\r
+-- 0x2 = Bus Write Repeat ( burst to single address )\r
+-- 0x3 = Bus Read Repeat ( burst read from single address )\r
+-- Sub-Slot 0xF = Power and Pin Control ( Write Only )\r
+-- \r
+-- SubSlot=0 : LocalBus\r
+-- Command\r
+-- 0 : Write\r
+-- 1 : Read\r
+--\r
+-- Ro : 0xF0FE3404 : \r
+-- 0xFF = Bus Idle ( NULLs )\r
+-- B0 0xF0 = New Bus Cycle to begin ( Nibble and bit orientation )\r
+-- B1 0xFE = Slot Number - Default is 0xFE for Ro traffic\r
+-- B2 0x3 = Sub-Slot within the chip (0-0xF)\r
+-- 0x4 = Command Nibble for Sub-Slot\r
+-- B3 0x04 = Number of Payload Bytes (0-255)\r
+-- \r
+--\r
+-- Revision History:\r
+-- Ver# When Who What\r
+-- ---- -------- -------- ---------------------------------------------------\r
+-- 0.1 10.04.15 khubbard Creation\r
+-- ***************************************************************************/\r
+`default_nettype none // Strictly enforce all nets to be declared\r
+ \r
+module mesa2lb\r
+(\r
+ input wire clk,\r
+ input wire reset,\r
+ input wire rx_byte_start,\r
+ input wire rx_byte_stop,\r
+ input wire rx_byte_rdy,\r
+ input wire [7:0] rx_byte_d,\r
+ output wire [7:0] tx_byte_d,\r
+ output wire tx_byte_rdy,\r
+ output reg tx_done,\r
+ input wire tx_busy,\r
+ output reg lb_wr,\r
+ output wire lb_rd,\r
+ output reg [31:0] lb_wr_d,\r
+ output reg [31:0] lb_addr,\r
+ input wire [31:0] lb_rd_d,\r
+ input wire lb_rd_rdy,\r
+ input wire oob_en,\r
+ input wire [31:0] oob_rd_d,\r
+ input wire oob_rd_rdy,\r
+ output reg prom_wr,\r
+ output wire prom_rd,\r
+ output reg [31:0] prom_wr_d,\r
+ output reg [31:0] prom_addr,\r
+ input wire [31:0] prom_rd_d,\r
+ input wire prom_rd_rdy\r
+); // module mesa2lb\r
+\r
+\r
+ reg lb_rd_loc;\r
+ reg [3:0] byte_cnt;\r
+ reg [31:0] addr_cnt;\r
+ reg [31:0] addr_len;\r
+ reg [31:0] dword_sr;\r
+ reg rx_byte_rdy_p1;\r
+ reg rx_byte_rdy_p2;\r
+ reg rx_byte_rdy_p3;\r
+ reg rx_byte_stop_p1;\r
+ reg rx_byte_stop_p2;\r
+ reg rx_byte_stop_p3;\r
+ reg header_jk;\r
+ reg wr_jk;\r
+ reg rd_jk;\r
+ reg rpt_jk;\r
+ reg [2:0] dword_stage;\r
+ reg dword_rdy;\r
+ reg reading;\r
+ reg rd_done;\r
+ reg rd_done_p1;\r
+ reg [31:0] lb_rd_sr;\r
+ reg [3:0] lb_rd_fsm;\r
+ reg rd_busy;\r
+ reg [7:0] rd_byte_d;\r
+//reg [7:0] rd_timeout_cnt;\r
+//reg rd_timeout_cnt_p1;\r
+ reg rd_byte_rdy;\r
+ reg lb_user_jk;\r
+ reg lb_prom_jk;\r
+ reg ro_header_rdy;\r
+\r
+\r
+// TODO: Write and Read burst Lengths should be reduced from 32bits for timing\r
+// TODO: A new cycle should always clear wr_jk and rd_jk in case a read timeout\r
+ assign tx_byte_d = rd_byte_d[7:0];\r
+ assign tx_byte_rdy = rd_byte_rdy;\r
+\r
+\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Shift a nibble into a byte shift register. \r
+// |---- Header ----|--- Payload ---|\r
+// 0 1 2 3\r
+// Write : <F0><00><00><08>[<ADDR><DATA>]\r
+// Read : <F0><00><00><08>[<ADDR><Length>]\r
+//-----------------------------------------------------------------------------\r
+always @ ( posedge clk ) begin : proc_lb1\r
+ rx_byte_rdy_p1 <= rx_byte_rdy;\r
+ rx_byte_rdy_p2 <= rx_byte_rdy_p1;\r
+ rx_byte_rdy_p3 <= rx_byte_rdy_p2;\r
+ rx_byte_stop_p1 <= rx_byte_stop;\r
+ rx_byte_stop_p2 <= rx_byte_stop_p1;\r
+ rx_byte_stop_p3 <= rx_byte_stop_p2;\r
+ dword_rdy <= 0;\r
+\r
+ if ( rx_byte_start == 1 ) begin\r
+ byte_cnt <= 4'd0;\r
+ header_jk <= 1;\r
+ end else if ( rx_byte_rdy == 1 ) begin \r
+ byte_cnt <= byte_cnt + 1; \r
+ end \r
+\r
+ // Shift bytes into a 32bit SR\r
+ if ( rx_byte_rdy == 1 ) begin \r
+ dword_sr[31:0] <= { dword_sr[23:0], rx_byte_d[7:0] };\r
+ end\r
+\r
+ // After we have 4 bytes, look for Slot=00,SubSlot=0,Command=0or1 (WR or RD)\r
+ if ( rx_byte_rdy_p2 == 1 && byte_cnt[1:0] == 2'd3 ) begin\r
+ dword_rdy <= 1;\r
+ header_jk <= 0;\r
+ if ( header_jk == 1 && wr_jk == 0 && rd_jk == 0 ) begin \r
+ // Note: This doesn't handle slot broadcast - only direct for LB Access\r
+ if ( dword_sr[31:16] == 16'hF000 ) begin\r
+ lb_user_jk <= 0;\r
+ lb_prom_jk <= 0;\r
+ if ( dword_sr[15:12] == 4'h0 ) begin\r
+ lb_user_jk <= 1;\r
+ end else if ( dword_sr[15:12] == 4'hE ) begin\r
+ lb_prom_jk <= 1;\r
+ end\r
+\r
+ if ( dword_sr[15:12] == 4'h0 || dword_sr[15:12] == 4'hE ) begin\r
+ if ( dword_sr[11:8] == 4'h0 || dword_sr[11:8] == 4'h2 ) begin\r
+ wr_jk <= 1;\r
+ dword_stage <= 3'b001;\r
+ end \r
+ if ( dword_sr[11:8] == 4'h1 || dword_sr[11:8] == 4'h3 ) begin\r
+ rd_jk <= 1;\r
+ dword_stage <= 3'b001;\r
+ end \r
+ // Repeat_JK Asserts to burst to/from single address\r
+ if ( dword_sr[11:8] == 4'h2 || dword_sr[11:8] == 4'h3 ) begin\r
+ rpt_jk <= 1;\r
+ end else begin\r
+ rpt_jk <= 0;\r
+ end\r
+ end // if ( dword_sr[15:12] == 4'h0 || dword_sr[15:12] == 4'hE ) begin\r
+ end // if ( dword_sr[31:16] == 16'hF000 ) begin\r
+ end else begin\r
+ // Payload\r
+ if ( wr_jk == 1 || rd_jk == 1 ) begin\r
+ // This shifts 001 to 010, 100 then halts at 100\r
+ // It records burst write stages of header,addr,data,data\r
+ dword_stage <= { ( dword_stage[2] | dword_stage[1] ), \r
+ dword_stage[0],\r
+ 1'b0 };\r
+ end\r
+ end // if ( wr_jk == 0 && rd_jk == 0 ) begin \r
+ end // if ( rx_byte_rdy_p2 == 1 && byte_cnt[1:0] == 2'd3 ) begin\r
+\r
+ //\r
+ if ( rx_byte_stop_p3 == 1 ) begin\r
+ wr_jk <= 0;\r
+ end\r
+ if ( rd_done == 1 && rd_done_p1 == 0 ) begin\r
+ rd_jk <= 0;\r
+ end\r
+ if ( reset == 1 ) begin\r
+ wr_jk <= 0;\r
+ rd_jk <= 0;\r
+ rpt_jk <= 0;\r
+ lb_user_jk <= 0;\r
+ lb_prom_jk <= 0;\r
+ header_jk <= 0;\r
+ end\r
+ \r
+end // proc_lb1\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Convert serial stream into parallel local bus\r
+//-----------------------------------------------------------------------------\r
+always @ ( posedge clk ) begin : proc_lb2\r
+ lb_wr <= 0;\r
+ prom_wr <= 0;\r
+ lb_rd_loc <= 0;\r
+//lb_wr_d <= 32'd0;\r
+//lb_addr <= 32'd0;\r
+//prom_wr_d <= 32'd0;\r
+//prom_addr <= 32'd0;\r
+ rd_done_p1 <= rd_done;\r
+ ro_header_rdy <= 0;\r
+\r
+ if ( dword_rdy == 1 && wr_jk == 1 ) begin\r
+ if ( dword_stage[1] == 1 ) begin\r
+ addr_cnt <= dword_sr[31:0];// 1st DWORD of WR is LB Address\r
+ end\r
+ if ( dword_stage[2] == 1 ) begin\r
+ lb_wr <= lb_user_jk;\r
+ prom_wr <= lb_prom_jk;\r
+ lb_addr <= addr_cnt[31:0];// Load the stored address\r
+ prom_addr <= addr_cnt[31:0];// Load the stored address\r
+ lb_wr_d <= dword_sr[31:0];// 2nd+ DWORDs or WR is Burst Data\r
+ prom_wr_d <= dword_sr[31:0];// 2nd+ DWORDs or WR is Burst Data\r
+ if ( rpt_jk == 0 ) begin\r
+ addr_cnt <= addr_cnt + 4; // Increment address for next cycle\r
+ end\r
+ end\r
+ end // if ( dword_rdy == 1 && wr_jk == 1 ) begin\r
+\r
+ if ( dword_rdy == 1 && rd_jk == 1 ) begin\r
+ if ( dword_stage[1] == 1 ) begin\r
+ addr_cnt <= dword_sr[31:0];// 1st DWORD of RD is LB Address\r
+ end\r
+ if ( dword_stage[2] == 1 ) begin\r
+ addr_len <= dword_sr[31:0];// 2nd DWORD of RD is Num DWORDs to Read\r
+ ro_header_rdy <= 1;// Send Ro Header as we know length of packet to send\r
+ end\r
+ end // if ( dword_rdy == 1 && rd_jk == 1 ) begin\r
+\r
+ if ( rd_jk == 0 ) begin\r
+ addr_len <= 32'd0;\r
+ rd_done <= 0;\r
+ reading <= 0;\r
+ end else begin\r
+ if ( addr_len != 32'd0 ) begin\r
+ if ( ro_header_rdy == 0 && rd_busy == 0 && lb_rd_loc == 0 ) begin\r
+ lb_rd_loc <= 1;\r
+ lb_addr <= addr_cnt[31:0];// Load stored address\r
+ prom_addr <= addr_cnt[31:0];// Load stored address\r
+ addr_len <= addr_len - 1; // Decrement DWORD length counter \r
+ reading <= 1;\r
+ if ( rpt_jk == 0 ) begin\r
+ addr_cnt <= addr_cnt + 4; // Increment address for next cycle\r
+ end\r
+ end\r
+ end else begin\r
+ if ( reading == 1 ) begin\r
+ rd_done <= 1;\r
+ end\r
+ end\r
+ end // if ( rd_jk == 0 ) begin\r
+\r
+//addr_cnt[31:12] <= 20'd0;// Harvest bits for timing\r
+//addr_len[31:12] <= 20'd0;// Harvest bits for timing\r
+// Max 63 DWORD Read as MesaBus payload max size is 255 bytes\r
+ addr_len[31:6] <= 26'd0;// Harvest bits for timing. \r
+\r
+end // proc_lb2\r
+ assign lb_rd = lb_rd_loc & lb_user_jk;\r
+ assign prom_rd = lb_rd_loc & lb_prom_jk;\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Shift the readback data out 1 byte at a time \r
+//-----------------------------------------------------------------------------\r
+always @ ( posedge clk ) begin : proc_lb3\r
+ tx_done <= 0;\r
+ rd_byte_rdy <= 0;\r
+ rd_byte_d <= 8'H00;\r
+//rd_timeout_cnt_p1 <= rd_timeout_cnt[7];\r
+\r
+ // Timeout after 128 clocks\r
+//if ( reset == 1 ) begin\r
+// rd_timeout_cnt <= 8'H00;// Stopped\r
+//end else begin\r
+// if ( lb_user_jk == 1 || lb_prom_jk == 1 ) begin\r
+// if ( lb_rd_loc == 1 ) begin\r
+// rd_timeout_cnt <= 8'H80;// Enable the count For 0-127\r
+// end else if ( lb_rd_rdy == 1 || prom_rd_rdy == 1 ) begin\r
+// rd_timeout_cnt[7] <= 0;// Stop the Count\r
+// rd_timeout_cnt_p1 <= 0;\r
+// end else if ( rd_timeout_cnt[7] == 1 ) begin\r
+// rd_timeout_cnt <= rd_timeout_cnt + 1;\r
+// end else if ( rd_timeout_cnt_p1 == 1 ) begin\r
+// rd_timeout_cnt <= 8'H00;// Stopped\r
+// lb_rd_sr <= 32'hDEADBEEF;\r
+// lb_rd_fsm <= 4'b1111;\r
+// rd_busy <= 1;\r
+// end\r
+// end\r
+//end\r
+\r
+ // rd_busy asserts when a 32bit Ro shift out is starting to pause bursts\r
+ if ( ro_header_rdy == 1 && ( lb_prom_jk == 1 || lb_user_jk == 1 ) ) begin\r
+ lb_rd_sr[31:8] <= 24'hF0FE00;\r
+ lb_rd_sr[7:0] <= { addr_len[5:0], 2'b00 };// Number of Return Bytes\r
+ lb_rd_fsm <= 4'b1111;\r
+ rd_busy <= 1;\r
+ end\r
+ if ( lb_rd_rdy == 1 && lb_user_jk == 1 ) begin\r
+ lb_rd_sr <= lb_rd_d[31:0];\r
+ lb_rd_fsm <= 4'b1111;\r
+ rd_busy <= 1;\r
+ end\r
+ if ( prom_rd_rdy == 1 && lb_prom_jk == 1 ) begin\r
+ lb_rd_sr <= prom_rd_d[31:0];\r
+ lb_rd_fsm <= 4'b1111;\r
+ rd_busy <= 1;\r
+ end\r
+ if ( oob_rd_rdy == 1 && oob_en == 1 ) begin\r
+ lb_rd_sr <= oob_rd_d[31:0];// oob stands for Out of Band signaling\r
+ lb_rd_fsm <= 4'b1111;\r
+ rd_busy <= 1;\r
+ end\r
+\r
+ if ( lb_rd_loc == 1 ) begin\r
+ rd_busy <= 1;\r
+ end\r
+\r
+ if ( lb_rd_fsm != 4'b0000 && rd_byte_rdy == 0 && tx_busy == 0 ) begin\r
+ rd_byte_d <= lb_rd_sr[31:24];\r
+ rd_byte_rdy <= 1;\r
+ lb_rd_sr <= { lb_rd_sr[23:0], 8'h00 };\r
+ lb_rd_fsm <= { lb_rd_fsm[2:0], 1'b0 };\r
+ if ( lb_rd_fsm == 4'b1000 ) begin\r
+ rd_busy <= 0;\r
+ if ( rd_jk == 0 && oob_en == 0 ) begin\r
+ tx_done <= 1;\r
+ end\r
+ end\r
+ end\r
+\r
+ if ( reset == 1 ) begin \r
+ lb_rd_fsm <= 4'b0000;\r
+ rd_busy <= 0;\r
+ end \r
+end // proc_lb3\r
+\r
+\r
+endmodule // mesa2lb\r