├── RS232_Debugger.exe ├── RS232_Debugger_Jan_14_2022.zip ├── SYNC_RS232_UART Simulation.png ├── RS232_Debugger_Hex-Editor_V1.2.zip ├── RS232_debug_read_req_parameter.png ├── RS232_Debugger_functional_simulation.png ├── README.md ├── sync_rs232_uart_v1.2.v ├── rs232_DEBUGGER_v1.2.v └── RS232_Debugger.bas /RS232_Debugger.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianHGinc/Verilog-RS232-Synch-UART-RS232-Debugger-and-PC-host-RS232-Hex-editor/HEAD/RS232_Debugger.exe -------------------------------------------------------------------------------- /RS232_Debugger_Jan_14_2022.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianHGinc/Verilog-RS232-Synch-UART-RS232-Debugger-and-PC-host-RS232-Hex-editor/HEAD/RS232_Debugger_Jan_14_2022.zip -------------------------------------------------------------------------------- /SYNC_RS232_UART Simulation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianHGinc/Verilog-RS232-Synch-UART-RS232-Debugger-and-PC-host-RS232-Hex-editor/HEAD/SYNC_RS232_UART Simulation.png -------------------------------------------------------------------------------- /RS232_Debugger_Hex-Editor_V1.2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianHGinc/Verilog-RS232-Synch-UART-RS232-Debugger-and-PC-host-RS232-Hex-editor/HEAD/RS232_Debugger_Hex-Editor_V1.2.zip -------------------------------------------------------------------------------- /RS232_debug_read_req_parameter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianHGinc/Verilog-RS232-Synch-UART-RS232-Debugger-and-PC-host-RS232-Hex-editor/HEAD/RS232_debug_read_req_parameter.png -------------------------------------------------------------------------------- /RS232_Debugger_functional_simulation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrianHGinc/Verilog-RS232-Synch-UART-RS232-Debugger-and-PC-host-RS232-Hex-editor/HEAD/RS232_Debugger_functional_simulation.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Verilog-RS232-Synch-UART-RS232-Debugger-and-PC-host-RS232-Hex-editor 2 | Verilog RS232 Synch-UART & RS232 Debugger and PC host RS232 Hex-editor. 3 | 4 | Debugger Hex Editor Changes v1.3, Jan 14, 2022. 5 | 6 | - Now has an 'ENDIAN' setting which now shows you the correct 16bit values for 16bit ints. 7 | - When editing cells, this also allows the use of the +/- keys to increment/decrement 16bit values with the new ENDIAN settings being taken into account. 8 | - Also has a new Quartus save 32bit .mif files. 9 | - Also, changing the ENDIAN before saving a 16bit or 32bit Quartus .mif file will also swap they byte order making it easy to render wide .mif files with reverse ENIANess. 10 | 11 | 12 | This is a Verilog core which contains a PC compatible high speed Synchronous RS-232 UART and RS232 debugger server and real-time PC client software hex-editor with 4 utility 8 bit input ports and 4 utility 8 bit output ports. 13 | 14 | The Verilog source is well documented in code. See the original project page from Nov 25, 2019 here: 15 | https://www.eevblog.com/forum/fpga/verilog-rs232-uart-and-rs232-debugger-source-code-and-educational-tutorial/ 16 | 17 | There are 3 pieces: 18 | 19 | 1) The ' SYNC_RS232_UART.v ' : A synchronizing RS232 transceiver. The 'synchronizing' transmitter with the receiver is crucial when interfacing with a PC as high speed full duplex communication require that the bit and word timing of serial data coming into the PC matches the clock and phase of the data the PC may be transmitting out at the same time. Many simple example Verilog RS232 UARTs arent capable of this. Read attached source code and see attached illustration to show you an example setup where my transmitter aligns itself to a received RS232 serial signal with a slightly different baud rate. 20 | 21 | 22 | 2) The ' RS232_Debugger.v ' : A Verilog module which uses the SYNC_RS232_UART.v, has an RS232 RXD input and TXD output. It also has a memory address output and 8 bit memory data input and output with a memory read request and memory write enable. This module also provides a reset output, 4 utility 8 bit output ports and 4 utility 8 bit input ports. Once again, everything is documented in the available 'RS232_Debugger.v' source code and I'm here to answer questions. 23 | 24 | 25 | 3) The ' RS232_Debugger.exe ' Viewer / HEX editor software. The software offers real-time viewing and editing of the user configured memory size set in the RS232_Debugger.v's memory address size parameter while also continuously displaying the values of the 4 utility 8 bit input ports as well as being able to set the values of the 4 utility 8 bit output ports. When the RS232 com port is closed, the RS232_Debugger.exe functions as a stand alone HEX / ASCII file editor which can edit up to 1 megabyte files. 26 | 27 | 28 | The Verilog code was written using pure synchronous logic. No fancy async-reset/presets, no S/R, J-K flipflops. These examples should easily integrate into any vendor's FPGAs EDA tool platform. If anyone out there has success, let us know. 29 | -------------------------------------------------------------------------------- /sync_rs232_uart_v1.2.v: -------------------------------------------------------------------------------- 1 | // ***************************************************************** 2 | // *** SYNC_RS232_UART.v V1.0, November 22, 2019 3 | // *** New Ver 1.2, April 12, 2021 - Moved parameters to be compatible with ModelSim. 4 | // *** 5 | // *** This transceiver follows slight baud timing errors introduced 6 | // *** by the external host interface's clock making the TDX output 7 | // *** clock timing synchronize to the RXD coming in allowing 8 | // *** high speed synchronous communications. A requirement 9 | // *** for PC RS232 full duplex synchronous communications. 10 | // *** 11 | // *** Written by Brian Guralnick. 12 | // *** Using generic Verilog code which only uses synchronous logic. 13 | // *** Well commented for educational purposes. 14 | // ***************************************************************** 15 | 16 | module sync_rs232_uart #( 17 | // Setup parameters 18 | parameter CLK_IN_HZ = 50000000, // Set to system input clock frequency 19 | parameter BAUD_RATE = 921600 // Set to desired baud rate 20 | )( 21 | input wire clk, // System clock 22 | input wire rxd, // RS232 serial input data pin 23 | output reg rx_rdy, // Pulsed high for 1 system clock when the received 8 bit data byte is ready 24 | output reg [7:0] rx_data, // Received 8 bit data byte. 25 | 26 | input wire ena_tx, // Signals the transmitter to latch the 8 bit data and begin transmitting 27 | input wire [7:0] tx_data, // 8 bit data byte input to be transmitted 28 | output reg txd, // RS232 serial output data pin 29 | output reg tx_busy, // High when transmitter is busy. Low when you may load a byte to transmit 30 | 31 | output reg rx_sample_pulse // For debugging RXD errors only. This is an output test pulse 32 | // aligned to when the receiver has sampled the RXD input. 33 | ) ; 34 | 35 | 36 | localparam RX_PERIOD = (CLK_IN_HZ / BAUD_RATE) -1 ; // Set's a reference counter size for each transmitted/received serial data bit 37 | localparam TX_PERIOD = (CLK_IN_HZ / BAUD_RATE) -1 ; 38 | 39 | // Receiver regs 40 | reg [15:0] rx_period ; 41 | reg [3:0] rx_position ; 42 | reg [9:0] rx_byte ; 43 | reg rxd_reg, last_rxd ; 44 | reg rx_busy, rx_last_busy ; 45 | 46 | // Transmitter regs 47 | reg [15:0] tx_period = 16'h0 ; 48 | reg [3:0] tx_position = 4'h0 ; 49 | reg [9:0] tx_byte = 10'b1111111111 ; 50 | reg [7:0] tx_data_reg = 8'b11111111 ; 51 | reg tx_run = 1'b0 ; 52 | 53 | 54 | 55 | //******************************************************************************************** 56 | // make the rx_trigger 'WIRE' equal to any new RXD input High to Low transition (IE start bit) 57 | // when the receiver is not busy receiving a byte 58 | //******************************************************************************************** 59 | wire rx_trigger ; 60 | assign rx_trigger = ( ~rxd_reg && last_rxd && ~rx_busy ); 61 | 62 | 63 | always @ (posedge clk) begin 64 | //******************************** 65 | // Receiver functions. 66 | //******************************** 67 | 68 | // register clock the UART RDX input signal. 69 | // This is a personal preference as I prefer FPGA inputs which don't directly feed combinational logic 70 | rxd_reg <= rxd; 71 | last_rxd <= rxd_reg; // create a 1 clock delay register of the rxd_reg serial bit 72 | 73 | rx_last_busy <= rx_busy; // create a 1 clock delay of the rx_busy resister. 74 | rx_rdy <= rx_last_busy && ~rx_busy; // create the rx_rdy out pulse for 1 single clock when the rx_busy flag has gone low signifying that rx_data is ready 75 | 76 | 77 | if ( rx_trigger ) begin // if a 'rx_trigger' event has taken place 78 | rx_period <= ( RX_PERIOD[15:0] >> 1 ) ; // set the period clock to half way inside a serial bit. This makes the best time to sample incoming 79 | // serial bits as the source baud rate may be slightly slow or fast maintaining a good data capture window all the way until the stop bit 80 | rx_busy <= 1'd1 ; // set the rx_busy flag to signify operation of the UART serial receiver 81 | rx_position <= 4'h9 ; // set the serial bit counter to position 9 82 | end else begin 83 | 84 | if ( rx_period==0 ) begin // if the receiver period counter has reached it's end 85 | rx_period <= RX_PERIOD[15:0] ; // reset the period counter 86 | rx_sample_pulse <= rx_busy ; // *** This is only a test pulse for debugging purposes 87 | 88 | if ( rx_position != 0 ) begin // if the receiver's bit position counter hasn't reached it's end 89 | rx_position <= rx_position - 1'd1 ; // decrement the position counter 90 | rx_byte[9] <= rxd_reg ; // load the receiver's serial shift regitser with the RXD input pin 91 | rx_byte[8:0] <= rx_byte[9:1] ; // shift the input serial shift register. 92 | 93 | end else begin // if the receiver's bit position counter reached 0 94 | rx_data <= rx_byte[9:2]; // load the output data register with the correct 8 bit contents of the serial input register 95 | rx_busy <= 1'b0; // turn off the serial receiver busy flag 96 | end 97 | 98 | end else begin // if the receiver period counter has not reached it's end 99 | rx_period <= rx_period - 1'b1; // just decrement the receiver period counter 100 | rx_sample_pulse <= 1'b0 ; // *** This is only a test pulse for debugging purposes 101 | end 102 | end // ~rx_trigger 103 | 104 | 105 | 106 | //*********************************************************** 107 | // SYNCHRONOUS! Transmitter functions 108 | // This was the most puzzling to get just right 109 | // So that both high and low speed intermittent 110 | // and continuous COM transactions would never 111 | // cause a byte error when communicating with 112 | // a PC as fast as possible. 113 | //*********************************************************** 114 | 115 | if (ena_tx) begin // If a transmit request comes in 116 | tx_data_reg <= tx_data ; // register a copy of the input data bus 117 | tx_busy <= 1 ; // Set the busy flag 118 | end 119 | 120 | 121 | // *********************************************************************************************************************** 122 | // This section prepares the data, controls and shift register during the middle of the previous transmission bit. 123 | // *********************************************************************************************************************** 124 | 125 | if ( tx_period == (TX_PERIOD[15:0] >> 1) ) begin // ******* at the center of a serial transmitter bit ******** 126 | 127 | if ( tx_position==1 ) begin // during the transmission of a stop bit 128 | tx_run <= 0 ; // turn off the transmitter running flag. This point is the beginning of when 129 | // a synchronous transmit word alignment to an incomming RXD rx_trigger is permitted 130 | 131 | if (tx_busy) begin // before the next start bit, if the busy flag was set, 132 | tx_byte[8:1] <= tx_data_reg[7:0] ; // load the register copy of the tx_data_reg into the serial shift register 133 | tx_byte[9] <= 1'b1 ; // Add a stop bit into the shift register's 10th bit 134 | tx_byte[0] <= 1'b0 ; // Add a start bit into the serial shift register's first bit 135 | tx_busy <= 1'b0 ; // Turn off the busy flag signifying that another transmit byte may be loaded 136 | end // into the tx_data_reg 137 | 138 | end else begin 139 | 140 | tx_byte[8:0] <= tx_byte[9:1] ; // at any other point than the stop-bit period, shift the serial tx_byte shift register 141 | tx_byte[9] <= 1'b1 ; // load a default stop bit into bit 10 of the serial shift register 142 | 143 | if ( tx_position == 0 ) tx_run <= ~txd ; // during the 'center of a serial 'START' transmitter bit' 144 | // if the serial UART TXD output pin has a start bit, turn on the transmitter running flag 145 | // which signifies the point where it is no longer permit-able to align a transmit word 146 | // to an incoming RXD byte potentially corrupting a serial transmission. 147 | end 148 | end 149 | 150 | 151 | // *********************************************************************************************************************** 152 | // This section takes the above prepared registers and sends them out during the transition edge of the tx_period clock 153 | // and during inactivity, or during the permitted alignment window, it will re-align the transmission period clock to 154 | // a potential incoming rx_trigger event. 155 | // *********************************************************************************************************************** 156 | 157 | // if a RXD start bit transition edge is detected and the transmitter is not running, 158 | // IE during the safe synchronous transmit word alignment period 159 | // set halfway between the center of transmitting the stop bit and next start bit 160 | 161 | if ( rx_trigger && ~tx_run ) begin 162 | 163 | tx_period <= TX_PERIOD[15:0] - 2'h2 ; // reset "SYNCHRONIZE" the transmit period timer to the rx_trigger event, recognizing that the rx_trigger is 164 | // delayed by 2 clocks, so we shave off 2 additional clock cycles for dead perfect parallel TXD output alignment. 165 | 166 | tx_position <= 1'b0 ; // force set the transmit reference position to the start bit 167 | txd <= tx_byte[0] ; // immediately set the UART TXD output to the serial out shift register's start bit. IE see above if(tx_busy) 168 | 169 | end else if ( tx_period==0 )begin // if the transmitter period counter has reached it's end 170 | 171 | tx_period <= TX_PERIOD[15:0] ; // reset the period counter 172 | txd <= tx_byte[0] ; // set the UART TXD output to the serial shift register's output. 173 | 174 | if ( tx_position == 0 ) tx_position <= 4'h9 ; // if the transmitter reference bit position counter is at the start bit, set it to bit 1. 175 | else tx_position <= tx_position - 1'b1 ; // otherwise, count down the position counter towards the stop bit 176 | 177 | end else tx_period <= tx_period - 1'b1 ; // if the transmit period has not reached it's end, it should count down. 178 | 179 | end // always 180 | 181 | endmodule 182 | -------------------------------------------------------------------------------- /rs232_DEBUGGER_v1.2.v: -------------------------------------------------------------------------------- 1 | // ********************************************************************************* 2 | // *** RS232_Debugger.v Ver 1.0. November 22, 2019 3 | // *** 4 | // *** New Ver 1.1, July 15, 2020 - Added parameter 'READ_REQ_1CLK' 5 | // *** New Ver 1.2, April 12, 2021 - Moved parameters to be compatible with ModelSim. 6 | // *** 7 | // *** This RS232_Debugger.v allows a PC to access, real-time 8 | // *** display & edit up to 16 megabytes of addressable memory. 9 | // *** (For PCs with a 921600 baud limit, 1 megabyte max memory 10 | // *** recommended as it takes 14 seconds to transfer that entire 11 | // *** block of memory. This improves with faster com ports as the FPGA 12 | // *** can easily achieve more than 10 megabaud with this Verilog code.) 13 | // *** 14 | // *** This RS232_Debugger.v can also generate a reset signal sent from the 15 | // *** PC control software and it also has 4 utility 8 bit input ports which 16 | // *** are continuously monitored and displayed in real-time. It also has 4 17 | // *** utility 8 bit output ports which can be set to any value at any time. 18 | // *** 19 | // *** In a minimum configuration, this module uses 370 logic cells + the required 20 | // *** SYNC_RS232_UART.v uses 107 logic cells for a total of 477 logic cells. The 21 | // *** total increases to 570 logic cells when every feature and all 24 address 22 | // *** bits are being used. 23 | // *** 24 | // *** Written by and (C) Brian Guralnick. 25 | // *** Using generic Verilog code which only uses synchronous logic. 26 | // *** Well commented and intended for educational purposes. 27 | // *** 28 | // ********************************************************************************* 29 | 30 | 31 | module rs232_debugger #( 32 | parameter CLK_IN_HZ = 50000000, // Set this parameter to your clock system clock frequency in Hertz 33 | parameter BAUD_RATE = 921600, // Keep this parameter at 921600 for the commanding RS232_Debugger PC software. 34 | parameter ADDR_SIZE = 20, // This sets the address size for the memory access. 24 is maximum, but unrealistic 35 | // at 921600 baud as it would take almost 4 minutes to transfer everything. 20 address bits, 36 | // 1048576 bytes / 1 megabyte takes around 14 seconds to transfer with the built in overhead. 37 | // For those who can access faster RS232 ports, these larger memory sizes could become more viable. 38 | 39 | parameter READ_REQ_1CLK = 0 // When 0, the 'host_rd_req' output stays high until a 'host_rd_rdy' is received. When 1, the 'host_rd_req' pulses for 1 clock only. 40 | )( 41 | 42 | input wire clk, // System clock. Recommend at least 20MHz for the 921600 baud rate. 43 | // This module is capable of over 100MHz on even the slowest FPGAs. 44 | 45 | output reg cmd_rst=0, // When sent by the PC RS232_Debugger utility, this outputs a high signal for 8 clock cycles. 46 | // It also runs high for 8 clock cycles during power-up. 47 | 48 | input wire rxd, // Connect this to the RS232 RXD input pin. 49 | output wire txd, // Connect this to the RS232 TXD output pin. 50 | 51 | output reg LED_txd, // Optionally wire this to a LED, it will go high whenever the RS232 TXD is active. 52 | output reg LED_rxd, // Optionally wire this to a LED, it will go high whenever the RS232 RXD is active. 53 | 54 | output wire host_rd_req, // This output will pulse high for 1 clock when a read request is taking place. 55 | input wire host_rd_rdy, // This input should be set high once the 'host_rdata[7:0]' input contains valid data. 56 | // Tie this input high if your read data will be always valid within 12 clock cycles since the hosr_rd_req. 57 | 58 | output reg host_wr_ena, // This output will pulse high for 1 clock when a write request is taking place. 59 | 60 | output wire [ADDR_SIZE-1:0] host_addr, // This output contains the requested read and write address. 61 | output reg [7:0] host_wdata, // This output contains the source RS232 8bit data to be written. 62 | input wire [7:0] host_rdata, // This input receives the 8 bit ram data to be sent to the RS232. 63 | // If 'host_rd_rdy' is tied to '1' the data needs to be valid within 12 clocks of the 'host_rd_req' pulse. 64 | 65 | // These are 4 8 bit utility input ports which are continuously read and displayed in the RS232_Debugger utility. 66 | input wire [7:0] in0, 67 | input wire [7:0] in1, 68 | input wire [7:0] in2, 69 | input wire [7:0] in3, 70 | 71 | 72 | // These are 4 8 bit utility output ports which are set by the RS232_Debugger utility. 73 | output reg [7:0] out0=0, 74 | output reg [7:0] out1=0, 75 | output reg [7:0] out2=0, 76 | output reg [7:0] out3=0 77 | ); 78 | 79 | reg [7:0] in_reg0,in_reg1,in_reg2,in_reg3; // These 'in_reg#[7:0]' will be used to latch all 4 'in#[7:0]' inputs in parallel before transmitting their state through the RS232 transceiver. 80 | 81 | 82 | localparam CLK_1KHz_PERIOD = CLK_IN_HZ / 1000 ; // The counter period for generating an internal 1 KHz timer 83 | localparam DEBUG_WDT_TIME = 4'd15; // Com activity watch dog timer. Time until a incomming Write to ram command is aborted due to inactive com. 84 | localparam LED_HOLD_TIME = 4'd15; // Keep the LED_rxd/txd signal high for at least this amount of ms time during RXD/TXD transactions. 85 | 86 | reg [17:0] tick_1KHz_counter ; // This reg is the counter for the main clock input which is used to generate the 1KHz timer. 87 | reg tick_1KHz ; // This reg will pulse for 1 'clk' cycle at 1KHz. 88 | reg [4:0] timeout_cnt; // This is a counter which is used for the communications watch dog timer which times out at the 'DEBUG_WDT' parameter count running at 1KHz speed. 89 | reg [4:0] led_txd_timeout, led_rxd_timeout; // These are timer counters used to keep the communication status LEDs on for the 'LED_HOLD_TIME' parameter count running at 1KHz speed. 90 | 91 | reg host_rd_req_r, host_rd_req_r1; 92 | assign host_rd_req = READ_REQ_1CLK ? (host_rd_req_r && !host_rd_req_r1) : host_rd_req_r ; // selects between a single clock pulse 'host_rd_req' or the original one which staye high until a 'host_rd_rdy' is received 93 | 94 | // ***************************************************************************************************************************************************************************** 95 | // **** Example command structure shown in RS232 received and transmitted hex bytes: 96 | // **** 97 | // **** Example #1: CMD_READ_BYTES (See figure #1) 98 | // **** << SETUP HEADER >> < > < > 99 | // **** Read host ram string ( 80 FF FF 00 00 00 00 00 00 52 65 61 64 00 01 00 04 52 65 61 64 00 01 00 04 ) Both copies must match for 100 | // **** The last 16 characters RX_Buffer string << Copy #1 of command >> << Copy #2 of command >> the command to be accepted. 101 | // **** 102 | // **** RX_Buffer #7,6,5,4= 32'h 52 65 61 64 = CMD_READ_BYTES 103 | // **** RX_Buffer #3,2,1= 24'h 00 01 00 = From Address 24'h000100 104 | // **** RX_Buffer #0 = 8'h 04 = Transfer 8'h04 + 1 = 5 bytes. 105 | // **** 106 | // **** The RS232_Debugger will then transmit 5 bytes read from host ram port. 107 | // **** Example #2: CMD_READ_BURST 108 | // **** << SETUP HEADER >> < > < > 109 | // **** Read host ram string ( 80 FF FF 00 00 00 00 00 00 52 65 61 50 00 80 00 0F 52 65 61 50 00 80 00 0F ) 110 | // **** The last 16 characters RX_Buffer string << Copy #1 of command >> << Copy #2 of command >> 111 | // **** 112 | // **** RX_Buffer #7,6,5,4= 32'h 52 65 61 50 = CMD_READ_BURST 113 | // **** RX_Buffer #3,2,1= 24'h 00 80 00 = From Address 24'h008000 114 | // **** RX_Buffer #0 = 8'h 0F = Transfer (8'h0F + 1) *256 = 4096 bytes. 115 | // **** 116 | // **** The RS232_Debugger will then transmit 4096 bytes read from host ram port. 117 | // **** 118 | // **** Example #3: CMD_WRITE_BYTES (See figure #2) 119 | // **** << SETUP HEADER >> < > < > 120 | // **** Read host ram string ( 80 FF FF 00 00 00 00 00 00 57 72 69 74 00 01 00 04 57 72 69 74 00 01 00 04 ) 121 | // **** The last 16 characters RX_Buffer string << Copy #1 of command >> << Copy #2 of command >> 122 | // **** 123 | // **** RX_Buffer #7,6,5,4= 32'h 57 72 69 74 = CMD_WRITE_BYTES 124 | // **** RX_Buffer #3,2,1= 24'h 00 01 00 = To Address 24'h000100 125 | // **** RX_Buffer #0 = 8'h 04 = Transfer 8'h7F + 1 = 5 bytes. 126 | // **** 127 | // **** The RS232_Debugger will now expect to receive 5 bytes which will be written 128 | // **** into the host ram. The 5 received characters will be echoed back as verification. 129 | // **** If there is a pause or delay for more than 0.1 seconds, write command halts/aborts. 130 | // **** 131 | // **** Example #4: CMD_SET_PORTS (See figure #3) 132 | // **** << SETUP HEADER >> < > < > 133 | // **** Read host ram string ( 80 FF FF 00 00 00 00 00 00 53 65 74 50 AA BB CC DD 53 65 74 50 AA BB CC DD ) 134 | // **** The last 16 characters RX_Buffer string << Copy #1 of command >> << Copy #2 of command >> 135 | // **** 136 | // **** RX_Buffer #7,6,5,4= 32'h 53 65 74 50 = CMD_SET_PORTS 137 | // **** RX_Buffer #3 = 8'h AA = Output port Out0[7:0] will be set to 8'hAA 138 | // **** RX_Buffer #2 = 8'h BB = Output port Out1[7:0] will be set to 8'hBB 139 | // **** RX_Buffer #1 = 8'h CC = Output port Out2[7:0] will be set to 8'hCC 140 | // **** RX_Buffer #0 = 8'h DD = Output port Out3[7:0] will be set to 8'hDD 141 | // **** 142 | // **** The RS232_Debugger will then transmit back the values of: 143 | // **** Ports In0[7:0], In1[7:0], In2[7:0], In3[7:0], then Parameter 'ADDR_SIZE[7:0]'. 144 | // **** 145 | // **** 146 | // ***************************************************************************************************************************************************************************** 147 | 148 | 149 | wire [31:0] CMD_READ_BYTES, CMD_READ_BURST, CMD_WRITE_BYTES, CMD_WRITE_BURST, CMD_RESET, CMD_SET_PORTS; // Set wire labels for all the command strings. 150 | reg [15*8+7:0] RX_buffer; // This 16 word * 8 bit character register will take in the RS232 data as an 8 bit word pipe, 16 characters long. 151 | wire [31:0] CMD_PREFIX ; // Define a 32 bit wire bus in the RX_buffer which contains the command prefix and CMD_SUFFIX 152 | wire [23:0] CMD_ADDRESS_POINTER ; // Define a 24 bit wire bus for the 'CMD_ADDRESS_POINTER' 153 | wire [7:0] CMD_TRANSFER_SIZE ; // Define an 8 bit wire bus for the 'CMD_TRANSFER_SIZE' 154 | 155 | reg [3:0] RXD_00_cnt; // This register will count the consecutive number of bytes = 8'h00 ahead of the command. It will reset to 0 if any other byte value is received. 156 | reg [3:0] RXD_FF_cnt; // This register will count the number of bytes = 8'hFF ahead of the command. It will reset to 0 if any other byte value other than 8'h00 is received. 157 | 158 | // Assign values to all the command wires 159 | wire CMD_HEADER, CMD_VERIFY; 160 | assign CMD_HEADER = ( RXD_FF_cnt==4'h2 && RXD_00_cnt==4'h6 ); // Two consecutive 8'hFF and then 6 consecutive 8'h00 must be transmitted 161 | // as a header before a command, otherwise, all potential received commands will be ignored. 162 | 163 | assign CMD_VERIFY = ( RX_buffer[15*8+7:8*8] == RX_buffer[7*8+7:0*8] ); // To verify authenticate an incoming command, the 2 consecutive identical copies 164 | // of the 8 byte command must match 165 | 166 | assign CMD_PREFIX = RX_buffer[7*8+7:4*8] ; // The point in the receive buffer is where the 4 character command is located 167 | assign CMD_READ_BYTES = 32'h52656164 ; // Read host ram and transmit to RS232, from 1 through 256 bytes. 168 | assign CMD_READ_BURST = 32'h52656150 ; // Page read host ram and transmit to RS232, from 256 through 65536 bytes. 169 | assign CMD_WRITE_BYTES = 32'h57726974 ; // Read RS232 data and write into host ram, from 1 through 256 bytes. 170 | assign CMD_WRITE_BURST = 32'h57726950 ; // Page Read RS232 data and write into host ram, from 256 through 65536 bytes. 171 | assign CMD_RESET = 32'h52657365 ; // Cycle the reset output command prefix 172 | assign CMD_SET_PORTS = 32'h53657450 ; // Set the general purpose output ports and read general purpose input ports + then transmit 'ADDR_SIZE' parameter. 173 | assign CMD_ADDRESS_POINTER = RX_buffer[3*8+7:1*8] ; // Point to the 3 8 bit words in the command's register which contains the 24 bit starting read and write address 174 | assign CMD_TRANSFER_SIZE = RX_buffer[0*8+7:0*8] ; // Point to the 8 bit word in the command's register which contains the number of bytes+1 to transfer 175 | // Or in the case of a R/W_BURST, set the byte transfer quantity to (CMD_TRANSFER_SIZE+1) * 256 176 | 177 | reg [16:0] byte_count; // This register will be used to count the number of bytes which were requested by 'CMD_TRANSFER_SIZE' to be received or transmitted through the RS232 transceiver. 178 | reg [23:0] host_addr_reg ; // This register will hold and count the host read and write address. 179 | reg [7:0] host_rdata_reg ; // when the 'host_rd_rdy' input goes high, this register will latch the 'host_rdata' input port. 180 | 181 | assign host_addr[ADDR_SIZE-1:0] = host_addr_reg[ADDR_SIZE-1:0]; // Assign the host register output port the the host_addr_reg register counter 182 | 183 | 184 | reg [1:0] Function ; // This register holds which of the 4 possible program functions the RS232_Debugger is running. 185 | wire [1:0] FUNC_WAIT, FUNC_READ, FUNC_WRITE, FUNC_SET_PORTS ; 186 | assign FUNC_WAIT = 2'h0 ; // This function state waits for incoming commands. When a valid command is received, it will setup the next function state. 187 | assign FUNC_READ = 2'h1 ; // This function state will read 'byte_count+1' bytes of host ram and transmit the contents to the RS232 port's TXD. 188 | assign FUNC_WRITE = 2'h2 ; // This function state will read 'byte_count+1' bytes from the RS232 port's RXD and send the data to the host ram + send a copy back to the RS232 port's TXD. 189 | assign FUNC_SET_PORTS = 2'h3 ; // This function state will send the the 4 in#[7:0] ports' values and then the 'ADDR_SIZE' parameter through the RS232 transceiver. 190 | 191 | 192 | reg [3:0] rst_clk=0; // This will be used as a counter to pulse out the 'cmd_rst' output pin for 8 clock cycles when commanded to by the RS232. 193 | reg [3:0] tx_cyc=0; // This counter will be used to slow down and sequence actions when transmitting bytes out through the RS232 transceiver. 194 | 195 | 196 | 197 | // ************************************************************************* 198 | // *** SYNC_RS232_UART.v setup. Read the SYNC_RS232_UART.v file to see how 199 | // *** I engineered this module and how I got the transmitter to function 200 | // *** synchronously with a PC's serial incoming RXD transmission. 201 | // *** 202 | // *** Timing diagrams on EEVBlog forum here: 203 | // *** 204 | // ************************************************************************* 205 | 206 | wire uart_tx_full; 207 | wire rxd_rdy; 208 | reg [4:0] ena_rxd_dly; // This register will receive the UART's 'rxd_rdy' pulse and serial shift that pulse along it's 5 bits. 209 | wire [7:0] uart_rbyte; 210 | reg uart_tx; 211 | reg [7:0] uart_tbyte; // This reg will hold the byte which is about to be transmitted 212 | 213 | sync_rs232_uart rs232_io ( .clk(clk), 214 | .rxd(rxd), // Goes to RXD Input Pin 215 | .txd(txd), // Goes to TXD output pin 216 | 217 | .rx_data(uart_rbyte), // Received data byte 218 | .rx_rdy(rxd_rdy), // 1 clock pulse high when the received data bit is ready 219 | 220 | .ena_tx(uart_tx), // Pulsed high for 1 clock when tx_data byte is ready to be sent 221 | .tx_data(uart_tbyte), // The byte which will be transmitted 222 | .tx_busy(uart_tx_full) ); // High when the 1 word FIFO in the UART's transmit buffer is full 223 | defparam 224 | rs232_io.CLK_IN_HZ = CLK_IN_HZ, 225 | rs232_io.BAUD_RATE = BAUD_RATE; 226 | 227 | 228 | always @ (posedge clk) begin 229 | 230 | // ****************************************************************** 231 | // ****** Generate a generic 1 KHz timer tick pulse. 232 | // ****************************************************************** 233 | if ( tick_1KHz_counter <= 18'h1 ) begin 234 | tick_1KHz_counter <= CLK_1KHz_PERIOD[17:0]; 235 | tick_1KHz <= 1'b1 ; 236 | end else begin 237 | tick_1KHz_counter <= tick_1KHz_counter - 1'b1 ; 238 | tick_1KHz <= 1'b0 ; 239 | end 240 | 241 | // ****************************************************************** 242 | // ****** Generate a status activity RXD and TXD led driver output. 243 | // ****** This routine keeps the LED outputs on long enough to 244 | // ****** visibly see as the data bursts are too short to be seen. 245 | // ****************************************************************** 246 | if (uart_tx_full) begin 247 | led_txd_timeout <= LED_HOLD_TIME ; 248 | LED_txd <= 1'b1 ; 249 | end else if ( led_txd_timeout!=5'h0 && tick_1KHz ) led_txd_timeout <= led_txd_timeout - 1'b1 ; 250 | else if ( led_txd_timeout==5'h0 ) LED_txd <= 1'b0 ; 251 | 252 | if (rxd_rdy) begin 253 | led_rxd_timeout <= LED_HOLD_TIME ; 254 | LED_rxd <= 1'b1 ; 255 | end else if ( led_rxd_timeout!=5'h0 && tick_1KHz ) led_rxd_timeout <= led_rxd_timeout - 1'b1 ; 256 | else if ( led_rxd_timeout==5'h0 ) LED_rxd <= 1'b0 ; 257 | 258 | // ****************************************************************** 259 | // ****************************************************************** 260 | 261 | cmd_rst <= ~rst_clk[3] ; // Register delay and invert latch bit 4 of the reset counter. 262 | if (~rst_clk[3]) begin // *** Generate an 8 clock wide reset pulse 263 | rst_clk <= rst_clk + 1'b1 ; // Count until bit 3 on the counter goes high. 264 | end else begin 265 | 266 | if (cmd_rst) begin // Last single 1 shot reset from the reset output signal 'cmd_rst'. 267 | host_addr_reg <= 24'h0 ; 268 | host_wr_ena <= 1'b0 ; // make sure we aren't writing ram. 269 | host_rd_req_r <= 1'b0 ; // make sure we aren't requesting a read from memory 270 | host_rd_req_r1 <= 1'b0 ; // make sure we aren't requesting a read from memory 271 | ena_rxd_dly[4:0] <= 5'h0 ; // clear out any possible RS232 transceiver rx_rdy 272 | RX_buffer[15*8+7:0] <= 128'h0 ; // clear out the entire 16 word by 8 bit character input command buffer. 273 | Function <= FUNC_WAIT ; // set the program state to the 'wait for incoming command' function. 274 | uart_tx <= 1'b0 ; // make sure no transmit character command is being sent to the RS232 transceiver. 275 | end else begin 276 | 277 | 278 | // ****************************************************************************************** 279 | // *** setup a sequential accessible delayed pipe of the RS232 transceiver's 'rx_rdy' signal. 280 | // ****************************************************************************************** 281 | ena_rxd_dly[0] <= rxd_rdy ; 282 | ena_rxd_dly[4:1] <= ena_rxd_dly[3:0] ; 283 | host_rd_req_r1 <= host_rd_req_r ; // Single pulse isolator for 1 shot host_rd_req output 284 | 285 | // ****************************************************************************************************************** 286 | // *** setup case statement for the 4 possible functions, FUNC_WAIT, FUNC_READ, FUNC_WRITE, FUNC_SET_PORTS 287 | // ****************************************************************************************************************** 288 | case (Function) 289 | 290 | 291 | // ************************************************************************************************************************************************************************************ 292 | // *** Beginning Function FUNC_WAIT. This function state waits for incoming commands. When a valid command is received, it will setup the next function state. 293 | // ************************************************************************************************************************************************************************************ 294 | FUNC_WAIT : begin 295 | 296 | host_rd_req_r <= 1'b0; // force off any ram transactions. 297 | host_wr_ena <= 1'b0; 298 | 299 | if (ena_rxd_dly[3]) begin // Note we are using the ena_rxd_dly[3] deliberately since if the 'FUNC_WRITE' is called, it uses a pre-setup time by triggering sequenced actions on earlier ena_rxd_dly[#]s 300 | 301 | RX_buffer[15*8+7:0] <= { RX_buffer[14*8+7:0] , uart_rbyte } ; // This will shift 1 byte at a time through the 16 character command buffer 302 | 303 | if ( RX_buffer[15*8+7:15*8]==8'h00 ) RXD_00_cnt <= RXD_00_cnt + (RXD_00_cnt!=3'h7); // test the last byte in the 16 character buffer and 304 | else RXD_00_cnt <= 3'h0 ; // count the number of bytes which are sequentially = 8'h00. 305 | 306 | if ( RX_buffer[15*8+7:15*8]==8'hFF ) RXD_FF_cnt <= RXD_FF_cnt + (RXD_FF_cnt!=3'h7); // test the last byte in the 16 character buffer and 307 | else if ( RX_buffer[15*8+7:15*8]!=8'h00 ) RXD_FF_cnt <= 3'h0 ; // count the number of bytes which are sequentially = 8'hFF 308 | 309 | end 310 | 311 | if ( CMD_HEADER && CMD_VERIFY ) begin // Test to see if the command prefix string meets the 2 bytes of 8'hFF, 312 | // then 6 bytes of 8'h00, and then 2 command string of 8 bytes each which are identical 313 | 314 | // ******************************************************************************************************** 315 | // *** setup case statement which will perform actions based on the 6 possible incoming CMD_PREFIX : 316 | // *** CMD_READ_BYTES, CMD_READ_BURST, CMD_WRITE_BYTES, CMD_WRITE_BURST, CMD_RESET, CMD_SET_PORTS 317 | // ******************************************************************************************************** 318 | case (CMD_PREFIX) 319 | 320 | 321 | // ******************************************************************************************************** 322 | // *** CMD_PREFIX case CMD_READ_BYTES. Read host ram and transmit to RS232, from 1 through 256 bytes. 323 | // ******************************************************************************************************** 324 | CMD_READ_BYTES : begin 325 | byte_count[16:8] <= 9'h0; 326 | byte_count[7:0] <= CMD_TRANSFER_SIZE ; 327 | host_addr_reg[23:0] <= CMD_ADDRESS_POINTER ; 328 | Function <= FUNC_READ ; 329 | tx_cyc <= 4'h0; 330 | RX_buffer[15*8+7:0] <= 128'h0; 331 | timeout_cnt <= DEBUG_WDT_TIME ; // set the receive abort timeout counter 332 | end // end of case CMD_READ_BYTES 333 | 334 | // ******************************************************************************************************** 335 | // *** CMD_PREFIX case CMD_WRITE_BYTES. Read RS232 data and write into host ram, from 1 through 256 bytes. 336 | // ******************************************************************************************************** 337 | CMD_WRITE_BYTES : begin 338 | byte_count[16:8] <= 9'h0; 339 | byte_count[7:0] <= CMD_TRANSFER_SIZE ; 340 | host_addr_reg[23:0] <= CMD_ADDRESS_POINTER ; 341 | Function <= FUNC_WRITE ; 342 | RX_buffer[15*8+7:0] <= 128'h0; 343 | timeout_cnt <= DEBUG_WDT_TIME ; // set the receive abort timeout counter 344 | end // end of case CMD_WRITE_BYTES 345 | 346 | // ******************************************************************************************************** 347 | // *** CMD_PREFIX case CMD_READ_BURST. Page read host ram and transmit to RS232, from 256 through 65536 bytes. 348 | // ******************************************************************************************************** 349 | CMD_READ_BURST : begin 350 | byte_count[16] <= 1'b0; 351 | byte_count[15:8] <= CMD_TRANSFER_SIZE ; 352 | byte_count[7:0] <= 8'hFF ; 353 | host_addr_reg[23:0] <= CMD_ADDRESS_POINTER ; 354 | Function <= FUNC_READ ; 355 | tx_cyc <= 4'h0; 356 | RX_buffer[15*8+7:0] <= 128'h0; 357 | timeout_cnt <= DEBUG_WDT_TIME ; // set the receive abort timeout counter 358 | end // end of case CMD_READ_BURST 359 | 360 | // ******************************************************************************************************** 361 | // *** CMD_PREFIX case CMD_WRITE_BURST. Page Read RS232 data and write into host ram, from 256 through 65536 bytes. 362 | // ******************************************************************************************************** 363 | CMD_WRITE_BURST : begin 364 | byte_count[16] <= 1'b0; 365 | byte_count[15:8] <= CMD_TRANSFER_SIZE ; 366 | byte_count[7:0] <= 8'hFF ; 367 | host_addr_reg[23:0] <= CMD_ADDRESS_POINTER ; 368 | Function <= FUNC_WRITE ; 369 | RX_buffer[15*8+7:0] <= 128'h0; 370 | timeout_cnt <= DEBUG_WDT_TIME ; // set the receive abort timeout counter 371 | end // end of case CMD_WRITE_BURST 372 | 373 | // ******************************************************************************************************** 374 | // *** CMD_PREFIX case CMD_RESET. Trigger the com_rst output. 375 | // ******************************************************************************************************** 376 | CMD_RESET : begin 377 | rst_clk <= 4'h0; // Clearing the rst_clk which will begin the 8 clock reset period 378 | Function <= FUNC_WAIT ; 379 | RX_buffer[15*8+7:0] <= 128'h0; 380 | end // end of case CMD_RESET 381 | 382 | // ********************************************************************************************************************************************* 383 | // *** CMD_PREFIX case CMD_SET_PORTS. Set the general purpose output ports and read general purpose input ports + the transmit 'ADDR_SIZE' parameter. 384 | // ********************************************************************************************************************************************* 385 | CMD_SET_PORTS : begin 386 | out0 <= RX_buffer[3*8+7:3*8] ; // The 4 out# ports were sent withing the RX_buffer command's suffix. 387 | out1 <= RX_buffer[2*8+7:2*8] ; // Usually, the address and data transfer size is stored here. 388 | out2 <= RX_buffer[1*8+7:1*8] ; 389 | out3 <= RX_buffer[0*8+7:0*8] ; 390 | // *** Parallel register all 4 peripheral input ports. 391 | in_reg0 <= in0 ; 392 | in_reg1 <= in1 ; 393 | in_reg2 <= in2 ; 394 | in_reg3 <= in3 ; 395 | 396 | byte_count[16] <= 1'b0 ; 397 | byte_count[15:0] <= 16'h4 ; // There are 5 bytes to be sent, the 4 in_reg#[7:0] registers and the 'ADDR_SIZE' parameter. 398 | Function <= FUNC_SET_PORTS ; 399 | tx_cyc <= 4'h0 ; 400 | RX_buffer[15*8+7:0] <= 128'h0 ; 401 | timeout_cnt <= DEBUG_WDT_TIME ; // set the receive abort timeout counter 402 | end // end of case CMD_SET_PORTS 403 | 404 | endcase 405 | // ******************************************************************************************************** 406 | // *** End of case (CMD_PREFIX) for the 6 possible commands: 407 | // *** CMD_READ_BYTES, CMD_READ_BURST, CMD_WRITE_BYTES, CMD_WRITE_BURST, CMD_RESET, CMD_SET_PORTS 408 | // ******************************************************************************************************** 409 | 410 | 411 | end // End of Command verification if ( CMD_HEADER && CMD_VERIFY ) 412 | 413 | 414 | end 415 | // ************************************************************************************************************************************************************************************ 416 | // *** Ending case Function FUNC_WAIT. 417 | // ************************************************************************************************************************************************************************************ 418 | 419 | 420 | 421 | // ************************************************************************************************************************************************************************************ 422 | // *** Beginning Function FUNC_READ. This function will read 'byte_count+1' bytes of host ram and transmit the contents to the RS232 port's TXD. 423 | // ************************************************************************************************************************************************************************************ 424 | FUNC_READ : begin 425 | 426 | if (~byte_count[16] && timeout_cnt!=5'h0 ) begin // keep on transmitting until byte counter elapses by counting below 0. 427 | 428 | if ( uart_tx ) timeout_cnt <= DEBUG_WDT_TIME ; // If a character is transmitted, reset the watch dog timeout counter 429 | else if ( tick_1KHz ) timeout_cnt <= timeout_cnt - 1'b1 ; // Otherwise, countdown the watch dog timer once at every 1KHz tick. 430 | 431 | if ( host_rd_rdy ) host_rdata_reg <= host_rdata ; // latch the host_rdata input if the host_read_rdy is set. 432 | 433 | if (~(uart_tx_full && tx_cyc==4'h0) && ~(~host_rd_rdy && tx_cyc==4'h1) ) begin // only run the tx_cyc counter when the UART RS232 transmitter 434 | // is ready to transmit the next character and the host_rd_ready 435 | // has gone high after tx_cyc 0 when the host_re_req pulse has been sent. 436 | tx_cyc <= tx_cyc + 1'b1; // increment this cycle counter 437 | 438 | if (tx_cyc==4'd0) host_rd_req_r <= 1'b1; // pulse the host_rd_req_r with the current valid address 439 | else host_rd_req_r <= 1'b0; 440 | 441 | if (tx_cyc==4'd13) uart_tbyte <= host_rdata_reg ; // expect the returned data ready within 12 clock cycles, and latch that data into the RS232 transmitter data input register 442 | 443 | if (tx_cyc==4'd14) uart_tx <= 1'b1; // Trigger the RS232 transmit data enable 444 | else uart_tx <= 1'b0; 445 | 446 | if (tx_cyc==4'd15) host_addr_reg <= host_addr_reg + 1'b1; // increment the host memory address 447 | if (tx_cyc==4'd15) byte_count <= byte_count - 1'b1; // decrement the byte transfer size counter 448 | end 449 | 450 | end else begin // byte_count cycles has completed or timeout WDT has elapsed, 451 | Function <= FUNC_WAIT; // leave FUNC_READ and switch back to FUNC_WAIT for the next command. 452 | uart_tx <= 1'b0; 453 | host_rd_req_r <= 1'b0; 454 | end 455 | 456 | end // End of case FUNC_READ 457 | // ************************************************************************************************************************************************************************************ 458 | // *** Ending of Function FUNC_READ. 459 | // ************************************************************************************************************************************************************************************ 460 | 461 | 462 | 463 | // ************************************************************************************************************************************************************************************ 464 | // *** Beginning Function FUNC_WRITE. This function will read 'byte_count+1' bytes from the RS232 port's RXD and send the data to the host ram + send a copy back to the RS232 port's TXD. 465 | // ************************************************************************************************************************************************************************************ 466 | FUNC_WRITE : begin 467 | 468 | if (~byte_count[16] && timeout_cnt!=5'h0 ) begin // keep on reading from RS232 until byte counter elapses, or the timeout counter has reached it's end 469 | 470 | if ( ena_rxd_dly[0] ) timeout_cnt <= DEBUG_WDT_TIME ; // If a character is received, reset the watch dog timeout counter 471 | else if ( tick_1KHz ) timeout_cnt <= timeout_cnt - 1'b1 ; // Otherwise, countdown the watch dog timer once at every 1KHz tick. 472 | 473 | 474 | if (ena_rxd_dly[0]) host_wdata <= uart_rbyte ; // copy RS232 received data byte to the host memory data output port 475 | if (ena_rxd_dly[0]) uart_tbyte <= uart_rbyte ; // copy RS232 received data byte to the RS232 transmitter output data port 476 | 477 | if (ena_rxd_dly[1]) host_wr_ena <= 1'b1; // Trigger the host memory write enable 478 | else host_wr_ena <= 1'b0; 479 | 480 | if (ena_rxd_dly[1]) uart_tx <= 1'b1; // echo back received character by triggering the RS232 transmit data enable 481 | else uart_tx <= 1'b0; 482 | 483 | if (ena_rxd_dly[3]) host_addr_reg <= host_addr_reg + 1'b1 ; // increment the host memory address 484 | if (ena_rxd_dly[3]) byte_count <= byte_count - 1'b1 ; // decrement the byte transfer size counter 485 | 486 | end else begin // byte_count cycles has completed or timeout WDT has elapsed, 487 | Function <= FUNC_WAIT ; // leave FUNC_WRITE and switch back to FUNC_WAIT for the next command. 488 | host_wr_ena <= 1'b0 ; 489 | byte_count[16] <= 1'b1 ; 490 | end 491 | 492 | end // End of case FUNC_WRITE 493 | // ************************************************************************************************************************************************************************************ 494 | // *** Ending of Function FUNC_WRITE. 495 | // ************************************************************************************************************************************************************************************ 496 | 497 | 498 | 499 | // ************************************************************************************************************************************************************************************ 500 | // *** Beginning of Function FUNC_SET_PORTS. This function will send the 'ADDR_SIZE' parameter + the 4 in#[7:0] ports' data through the RS232's port's TXD. 501 | // ************************************************************************************************************************************************************************************ 502 | FUNC_SET_PORTS : begin 503 | 504 | if (~byte_count[16]) begin // keep on transmitting until byte counter elapses 505 | 506 | if (~(uart_tx_full && tx_cyc==4'h0)) begin 507 | 508 | tx_cyc <= tx_cyc + 1'b1 ; 509 | 510 | if (tx_cyc==4'd13) begin 511 | case (byte_count[2:0]) // Set the RS232 transmitter's data port with the correct data during the correct byte number 512 | 3'h4 : uart_tbyte <= in_reg0 ; 513 | 3'h3 : uart_tbyte <= in_reg1 ; 514 | 3'h2 : uart_tbyte <= in_reg2 ; 515 | 3'h1 : uart_tbyte <= in_reg3 ; 516 | 3'h0 : uart_tbyte <= ADDR_SIZE[7:0] ; 517 | endcase // case (byte_count[2:0]) 518 | end 519 | 520 | if (tx_cyc==4'd14) uart_tx <= 1'b1 ; // Trigger the RS232 transmit data enable 521 | else uart_tx <= 1'b0 ; 522 | 523 | if (tx_cyc==4'd15) byte_count <= byte_count - 1'b1 ; // decrement the byte transfer size counter 524 | 525 | end 526 | 527 | end else begin // byte_count cycles has completed, leave FUNC_SET_PORTS and switch back to FUNC_WAIT for the next command. 528 | Function <= FUNC_WAIT ; 529 | uart_tx <= 1'b0 ; 530 | host_rd_req_r <= 1'b0 ; 531 | end 532 | 533 | end // End of case FUNC_WRITE_PORTS 534 | // ************************************************************************************************************************************************************************************ 535 | // *** Ending of Function FUNC_SET_PORTS. 536 | // ************************************************************************************************************************************************************************************ 537 | 538 | 539 | 540 | endcase // Case (Function) 541 | // ****************************************************************************************************************** 542 | // *** End of case statement for the 4 possible functions, FUNC_WAIT, FUNC_READ, FUNC_WRITE, FUNC_SET_PORTS 543 | // ****************************************************************************************************************** 544 | 545 | 546 | end // ~rst 547 | end // ~soft_rst 548 | end // always @posedge 549 | endmodule 550 | -------------------------------------------------------------------------------- /RS232_Debugger.bas: -------------------------------------------------------------------------------- 1 | ' *********************************************************************** 2 | ' ***** 3 | ' ***** RS232_Debugger PC - Bridge to - RS232_Debugger.v FPGA Verilog 4 | ' ***** 5 | ' ***** Designed to be compiled with FREEBASIC 6 | ' ***** https://www.freebasic.net/ 7 | ' ***** 8 | ' ***** Written By Brian Guralnick. November 2019 9 | ' 10 | ' ***** V1.2 - August 13, 2020 11 | ' ***** Patched ascii display bug where character 0xFF sometimes showed 12 | ' ***** old characters from a previous page refresh. 13 | ' 14 | ' *********************************************************************** 15 | 16 | const MAX_MEM_ALLOC = 1048576 '16384 '1048576 17 | const COM_CACHE = 2048: REM number of allowed sequential bytes to be sent and received. FOR FTDI FT232 serial cables, use 2048. 1/2 their fifo size. 18 | const COM_PRE_TIMEOUT = 2 : REM time in ms to wait for flush to take effect 19 | const COM_POST_TIMEOUT = 5 : REM 20 time in ms to wait for GPU to respond before considering an error 20 | const COM_FLUSH = 0 : REM 1 = send 272 null characters before every command 0 = high speed 21 | const COM_WAIT = 0 : REM 1 = wait and flush an characters in the PC's RDX before beginning to transmit 22 | const COM_VERBOSE = 0 : REM 1= print all com transaction debug information, 2 = print mouse coordinates and keypresses 23 | const SLEEP_TIME = 1 : REM The amount of time to sleep in ms between screen refresh and COM access. Use at least 1 for good multitasking 24 | 25 | const TXT_BOX_x = 20 26 | const TXT_BOX_y = 25 27 | 28 | 29 | Declare Sub print_setup() 30 | Declare Sub print_hex() 31 | Declare Sub print_dec() 32 | Declare Sub print_mouse() 33 | Declare sub print_select() 34 | Declare Sub gpu_printadr() 35 | Declare Sub color_rg( colm as ubyte, yp as ubyte, xp as ubyte ) 36 | Declare Sub ascii_enter() 37 | Declare Sub hex_enter() 38 | Declare Sub inc_cursor(xofs as byte, yofs as byte) 39 | Declare Sub put_undo() 40 | Declare Sub get_undo() 41 | Declare Sub do_commands() 42 | Declare Sub print_ports() 43 | Declare sub click_binary(xp as integer, yp as integer, eb as Ubyte) 44 | Declare Sub open_com() 45 | Declare Sub close_com() 46 | 47 | 48 | Declare Sub read_gpu(mbase as integer, msize as integer) 49 | Declare Sub write_gpu(mbase as integer, msize as integer) 50 | Declare Sub read_gpu_all(mbase as integer, msize as integer) 51 | Declare Sub write_gpu_all(mbase as integer, msize as integer) 52 | Declare Sub com_setport() 53 | 54 | Declare Sub save_file(fname as string, start as integer, size as integer) 55 | Declare Sub load_file(fname as string, start as integer, size as integer) 56 | Declare Sub save_dialog() 57 | Declare Sub load_dialog() 58 | Declare Sub save_mif() 59 | Declare Sub save_mif16() 60 | Declare Sub save_mif32() 61 | Declare Sub file_dialog( i as string, fn as string ) 62 | Declare Sub edit16( i as integer ) 63 | Declare Sub enter16( i as integer ) 64 | Declare Sub box( i as integer ) 65 | declare sub show_errors(i as integer) 66 | 67 | Declare Sub inputhex (i as string) 68 | Declare Sub inputdec (i as string) 69 | 70 | 71 | function phex24(byval i As Integer) As String 72 | dim as string d 73 | d = hex(i) 74 | if i<16 then d = "0" + d 75 | if i<256 then d = "0" + d 76 | if i<4096 then d = "0" + d 77 | if i<65536 then d = "0" + d 78 | if i<1048576 then d = "0" + d 79 | function = d 80 | end function 81 | 82 | function phex16(byval i As Integer) As String 83 | dim as string d 84 | d = hex(i) 85 | if i<16 then d = "0" + d 86 | if i<256 then d = "0" + d 87 | if i<4096 then d = "0" + d 88 | function = d 89 | end function 90 | 91 | function p099(byval i As Integer) As String 92 | dim as string d 93 | d = str(i) 94 | if i<10 then d = " " + d 95 | function = d 96 | end function 97 | 98 | function px99(byval i As Integer) As String 99 | dim as string d 100 | d = str(i) 101 | if i<10 then d = "0" + d 102 | function = d 103 | end function 104 | 105 | function p999(byval i As Integer) As String 106 | dim as string d 107 | d = str(i) 108 | if i<100 then d = "0" + d 109 | if i<10 then d = "0" + d 110 | function = d 111 | end function 112 | 113 | function px999(byval i As Integer) As String 114 | dim as string d 115 | d = str(i) 116 | if i<100 then d = " " + d 117 | if i<10 then d = " " + d 118 | function = d 119 | end function 120 | 121 | function p9999(byval i As Integer) As String 122 | dim as string d 123 | d = str(i) 124 | if i<1000 then d = "0" + d 125 | if i<100 then d = "0" + d 126 | if i<10 then d = "0" + d 127 | function = d 128 | end function 129 | 130 | function px9999(byval i As Integer) As String 131 | dim as string d 132 | d = str(i) 133 | if i<1000 then d = " " + d 134 | if i<100 then d = " " + d 135 | if i<10 then d = " " + d 136 | function = d 137 | end function 138 | 139 | function p99999(byval i As Integer) As String 140 | dim as string d 141 | d = str(i) 142 | if i<10000 then d = "0" + d 143 | if i<1000 then d = "0" + d 144 | if i<100 then d = "0" + d 145 | if i<10 then d = "0" + d 146 | function = d 147 | end function 148 | 149 | function px99999(byval i As Integer) As String 150 | dim as string d 151 | d = str(i) 152 | if i<10000 then d = " " + d 153 | if i<1000 then d = " " + d 154 | if i<100 then d = " " + d 155 | if i<10 then d = " " + d 156 | function = d 157 | end function 158 | 159 | dim Shared as string ink, stemp, cmd_write, cmd_write_page, cmd_saddr, cmd_read, cmd_read_page, cmd_reset, cmd_null16, cmd_prefix, com_num, cmd_setp, com_port 160 | dim Shared as ubyte ser_byte,ENDIAN 161 | dim Shared as integer gpu_addr, gpu_addr_now, ser_rxbuf, x, y, z, c, hp, undobase, MAX_MEM 162 | dim shared as integer mx,my,mb,mw,mwl,mbl,mwd,mcx1,mcy1,mcz,mcx2,mcy2,mcx,mcy, edit_mode, edit_pos 163 | dim shared as integer m2cx1,m2cy1,m2cz,m2cx2,m2cy2,m2cx,m2cy,edit_col 164 | Dim Shared read_buffer (0 To MAX_MEM_ALLOC) As Ubyte 165 | Dim Shared undo_buffer (0 To 256) As Ubyte 166 | Dim Shared verify_buffer (0 To COM_CACHE) As Ubyte 167 | Dim Shared phex8 (0 To 255) As string 168 | Dim Shared asc_str (0 To 255) As string 169 | Dim Shared bin_str (0 To 255) As string 170 | Dim Shared in_port (0 to 4) As Ubyte 171 | Dim Shared out_port (0 to 3) As Ubyte 172 | 173 | dim Shared as integer mstart,mstop,mpos 174 | 175 | Dim Shared com_buffer (0 To 16) As Ubyte 176 | dim shared as integer com_addr, com_bytepos, com_command, com_timer, com_txp, com_rxp, com_sxp, com_rx_error, com_tx_error 177 | 178 | dim shared as string d_filename 179 | dim shared as integer d_membase, d_memsize 180 | 181 | ScreenRes 720,560,16,0,0 182 | cmd_null16 = chr(0) + chr(0) + chr(0) + chr(0) + chr(0) + chr(0) + chr(0) + chr(0) + chr(0) + chr(0) + chr(0) + chr(0) + chr(0) + chr(0) + chr(0) + chr(0) 183 | cmd_prefix = chr(128) + chr(255) + chr(255) + chr(0) + chr(0) + chr(0) + chr(0) + chr(0) + chr(0) 184 | cmd_write = "Writ" :rem The next 3 BYTEs defines the base address and the next byte defines the number of bytes to write 185 | cmd_read = "Read" :rem The next 3 BYTEs defines the base address and the next byte defines the number of bytes to read 186 | cmd_write_page = "WriP" :rem The next 3 BYTEs defines the base address and the next byte defines the number of 256 bytes to write 187 | cmd_read_page = "ReaP" :rem The next 3 BYTEs defines the base address and the next byte defines the number of 256 bytes to read 188 | cmd_setp = "SetP" :rem The next 3 BYTEs defines the base address and the next byte defines the number of bytes to read 189 | cmd_reset = "ResetNow" 190 | cmd_reset = cmd_null16 + cmd_prefix + cmd_reset + cmd_reset: Rem this is the full reset sequence 191 | 192 | asc_str(0) = " 0 0 0 0" 193 | asc_str(1) = " 0 0 0 1" 194 | asc_str(2) = " 0 0 1 0" 195 | asc_str(3) = " 0 0 1 1" 196 | asc_str(4) = " 0 1 0 0" 197 | asc_str(5) = " 0 1 0 1" 198 | asc_str(6) = " 0 1 1 0" 199 | asc_str(7) = " 0 1 1 1" 200 | asc_str(8) = " 1 0 0 0" 201 | asc_str(9) = " 1 0 0 1" 202 | asc_str(10) = " 1 0 1 0" 203 | asc_str(11) = " 1 0 1 1" 204 | asc_str(12) = " 1 1 0 0" 205 | asc_str(13) = " 1 1 0 1" 206 | asc_str(14) = " 1 1 1 0" 207 | asc_str(15) = " 1 1 1 1" 208 | 209 | 210 | MAX_MEM = MAX_MEM_ALLOC 211 | for x=0 to 255 212 | bin_str(x) = asc_str(int(x/16)) + asc_str(x and 15) + " " 213 | next x 214 | 215 | 216 | for x=0 to 255 217 | phex8(x) = hex(int(x/16)) + hex((x and 15)) 218 | read_buffer(x) = x:rem fill dummy data 219 | asc_str(x) = "." 220 | if x<>7 and x<>0 and x<>32 and x<>13 and not (x>=8 and x<=10) then asc_str(x)=chr(x): rem remove screen bell sound 221 | next x 222 | 223 | ' This dummy fills a 16bit wide counter into memory 224 | 'for x=0 to MAX_MEM/2-1 225 | 'read_buffer(x*2) = int(x/256) and 255:rem fill dummy data 226 | 'read_buffer(x*2+1) = int(x) and 255:rem fill dummy data 227 | 'next x 228 | 229 | for x=0 to MAX_MEM-1 230 | read_buffer(x) = 0 231 | next x 232 | 233 | 234 | close_com() 235 | print_setup() 236 | 237 | 238 | 239 | 240 | ' Wait for keyboard input 241 | 242 | 243 | getmouse mx,my,mw,mb:mbl=mb:mwl=mw 244 | ink=inkey 245 | ink=inkey 246 | ink="" 247 | while (ink<>chr(27) or edit_mode=1) and asc(mid(ink,2,1))<>107 248 | 249 | ink=inkey 250 | do_commands() 251 | 252 | wend : ' program quit 253 | 254 | close #1 255 | end 256 | 257 | 258 | 259 | 260 | sub print_setup() 261 | color rgb(224,224,64),rgb(0,0,0) 262 | cls 263 | locate 52,1: 264 | ? "Keys: PGUP & PGDN & Arrows = Scroll Up / Down Home & End = Top and Bottom of memory" 265 | ? " +CTRL+ = Scroll faster ESC = Quit" 266 | ? " [r] = re-read entire GPU ram [w] = write entire GPU ram" 267 | ? " [e] = Swap Endian " 268 | ? " Click mouse to select either hex numbers or ASCII text. Use +/-, Wheel mouse," 269 | ? " click on the the binary bits or decimal #, or type to edit the memory." 270 | ? " [CTRL-z] To undo changes. Hit ENTER/RMB/ESC to exit editing memory."; 271 | 272 | 273 | locate 39,60:?"SHIFT-S Save Debug_quick_file1" 274 | locate 40,60:?"SHIFT-L Load Debug_quick_file1" 275 | locate 41,60:?"CTRL -S Save Debug_quick_file2" 276 | locate 42,60:?"CTRL -L Load Debug_quick_file2" 277 | locate 43,60:?"[l] Load Binary" 278 | locate 44,60:?"[s] Save Binary" 279 | 280 | locate 45,60:?"[q] Save 8 bit Quartus .mif" 281 | locate 46,60:?"[Q] Save 16 bit Quartus .mif" 282 | locate 47,60:?"CTRL-Q Save 32 bit Quartus .mif" 283 | locate 48,60:?"CTRL-R RESET GPU" 284 | locate 49,60:?"CTRL-O Open RS232 com port" 285 | locate 50,60:?"CTRL-C Close RS232 com port" 286 | 287 | 288 | for y=0 to 8 289 | color_rg(1,y+62,1 ):? ,,," "; 290 | color_rg(2,y+62,45):? ,,," "; 291 | next y 292 | 293 | color rgb(255,255,255),rgb(0,0,255) 294 | if ENDIAN=0 then locate 1,58:? " Little Endian "; 295 | if ENDIAN=1 then locate 1,58:? " Big Endian "; 296 | color rgb(224,224,224),rgb(0,0,0) 297 | 298 | 299 | if com_num<>"" then color_rg(0,60,1):? com_port; 300 | if com_num="" then color_rg(2,60,1):? " Com Disabled! File hex editor mode. "; 301 | 302 | end sub 303 | 304 | 305 | 306 | sub do_commands() 307 | if ink="" and edit_mode=0 then read_gpu(gpu_addr,256) 308 | if ink="" and edit_mode=1 then write_gpu(gpu_addr,256) 309 | if ink="" then com_setport() 310 | 311 | if len(ink)<>0 and COM_VERBOSE=2 then locate 60,32:? len(ink),asc(ink),asc(mid(ink,2,1)),, 312 | 313 | if SLEEP_TIME<>0 then sleep SLEEP_TIME,0: REM helps allow allow system multitasking 314 | 315 | if edit_mode = 0 then 316 | z= asc(mid(ink,1,1)) 317 | if ink="L" then load_file("Debug_quick_file1.bin",0,MAX_MEM) 318 | if ink="S" then save_file("Debug_quick_file1.bin",0,MAX_MEM) 319 | if z = 12 then load_file("Debug_quick_file2.bin",0,MAX_MEM) 320 | if z = 19 then save_file("Debug_quick_file2.bin",0,MAX_MEM) 321 | 322 | if ink="l" then put_undo():load_dialog() 323 | if ink="s" then save_dialog() 324 | if ink="q" then save_mif() 325 | if ink="Q" then save_mif16() 326 | if z = 17 then save_mif32() 327 | 328 | if ink="r" then read_gpu_all(0,MAX_MEM) 329 | if ink="w" then write_gpu_all(0,MAX_MEM) 330 | 331 | if ink="e" then 332 | ENDIAN = ENDIAN xor 1 333 | color rgb(255,255,255),rgb(0,0,255) 334 | if ENDIAN=0 then locate 1,58:? " Little Endian "; 335 | if ENDIAN=1 then locate 1,58:? " Big Endian "; 336 | color rgb(224,224,224),rgb(0,0,0) 337 | endif 338 | 339 | 340 | if asc(mid(ink,1,1))=3 then close_com() 341 | if asc(mid(ink,1,1))=15 then open_com() 342 | 343 | 344 | if asc(mid(ink,2,1))=71 then gpu_addr=0 345 | if asc(mid(ink,2,1))=79 then gpu_addr=(MAX_MEM-256) 346 | 347 | if asc(mid(ink,2,1))=132 then gpu_addr=gpu_addr-1024 348 | if asc(mid(ink,2,1))=118 then gpu_addr=gpu_addr+1024 349 | if asc(mid(ink,2,1))=73 then gpu_addr=gpu_addr-256 350 | if asc(mid(ink,2,1))=81 then gpu_addr=gpu_addr+256 351 | 352 | if asc(mid(ink,2,1))=72 then gpu_addr=gpu_addr-16 353 | if asc(mid(ink,2,1))=80 then gpu_addr=gpu_addr+16 354 | 355 | if asc(mid(ink,2,1))=141 then gpu_addr=gpu_addr-64 356 | if asc(mid(ink,2,1))=145 then gpu_addr=gpu_addr+64 357 | 358 | z= asc(mid(ink,1,1)) 359 | if z=26 then get_undo():write_gpu(gpu_addr,256) 360 | if z=18 then for x=0 to 32:? #1,cmd_null16; :next x: ?#1,cmd_reset; : REM Reset the GPU 361 | 362 | 363 | end if 364 | 365 | 366 | if edit_mode = 1 then : REM Editing values 367 | z= asc(mid(ink,1,1)) 368 | if z=13 or z=27 or mb=2 then ink="":edit_mode=0: REM Leaving edit mode 369 | if z=26 then get_undo: REM Leaving edit mode 370 | 371 | if z>31 and edit_pos=1 and z<128 then ascii_enter() 372 | if (z>=48 and z<=57) or (z>=asc("a") and z<=asc("f")) and edit_pos = 0 then hex_enter() 373 | 374 | if ink="+" and edit_pos=0 then edit16(1) 375 | if ink="-" and edit_pos=0 then edit16(-1) 376 | 377 | if asc(mid(ink,2,1))=72 then inc_cursor(0,-1) 378 | if asc(mid(ink,2,1))=80 then inc_cursor(0,1) 379 | if asc(mid(ink,2,1))=75 then inc_cursor(-1,0) 380 | if asc(mid(ink,2,1))=77 then inc_cursor(1,0) 381 | 382 | 383 | 384 | end if 385 | 386 | 387 | mbl=mb 388 | getmouse mx,my,mw,mb 389 | if mb=-1 then mbl=mb 390 | if mb<>-1 and mbl=-1 then mwl=mw:mbl=0 391 | if mb<>-1 then mwd=mwl-mw:mwl=mw 392 | if mb=-1 then mwd=0 393 | if COM_VERBOSE=2 then locate 49,1:? mx,my,mw,mb; 394 | if edit_mode=0 and my<400 then gpu_addr=gpu_addr + (mwd*16) : rem mouse wheel scroll 395 | 396 | if gpu_addr<0 then gpu_addr=0 397 | if gpu_addr>(MAX_MEM-256) then gpu_addr=(MAX_MEM-256) 398 | 399 | 400 | if edit_mode=1 and my<400 then read_buffer(mcz) = read_buffer(mcz) + mwd : REM Mouse wheel edit 401 | 402 | print_hex() 403 | print_mouse() 404 | print_ports() 405 | 406 | end sub 407 | 408 | 409 | sub print_ports() 410 | color_rg(1,1,1):? " RS232 Address Size = ";in_port(4);" = ";(2^in_port(4));" bytes."; 411 | 412 | for y=0 to 3 413 | dim as string d 414 | 415 | d = " In" + str(y) + "[7:0]=8'b" + bin_str(in_port(y)) + "=8'h" + phex8(in_port(y)) + "=8'd" + p999(in_port(y)) + ". " 416 | color_rg(1,y*2+63,1):? d; 417 | 418 | d = " Out" + str(y) + "[7:0]=8'b" + bin_str(out_port(y)) + "=8'h" + phex8(out_port(y)) + "=8'd" + p999(out_port(y)) + ". " 419 | color_rg(2,y*2+63,45):? d; 420 | 421 | click_binary(60, y*2+63, y) 422 | 423 | 424 | next y 425 | 426 | 427 | 428 | end sub 429 | 430 | 431 | 432 | 433 | Sub edit16( i as integer ) 434 | 435 | if ENDIAN=1 then 436 | x = read_buffer(int(mcz/2)*2+0)*256 + read_buffer(int(mcz/2)*2+1) 437 | x=x+i:x=x and 65535 438 | read_buffer(int(mcz/2)*2+0) = int(x/256) 439 | read_buffer(int(mcz/2)*2+1) = x and 255 440 | else 441 | x = read_buffer(int(mcz/2)*2+1)*256 + read_buffer(int(mcz/2)*2+0) 442 | x=x+i:x=x and 65535 443 | read_buffer(int(mcz/2)*2+1) = int(x/256) 444 | read_buffer(int(mcz/2)*2+0) = x and 255 445 | endif 446 | 447 | end sub 448 | 449 | 450 | Sub inputhex( i as string ) 451 | dim as string i1 452 | box(7):z=-1 453 | color_rg(7,TXT_BOX_y+0,TXT_BOX_x):? i; 454 | 455 | input i1 456 | if i1<>"" then 457 | if mid(i1,1,2)="0x" then i1=mid(i1,3,len(i1)-2) 458 | if mid(i1,1,1)="$" then i1=mid(i1,2,len(i1)-1) 459 | i1 = "&H" + i1 460 | z= val(i1) 461 | end if 462 | 463 | box(0) 464 | end sub 465 | 466 | 467 | 468 | Sub inputdec( i as string ) 469 | dim as string i1 470 | box(7):z=-1 471 | color_rg(7,TXT_BOX_y+0,TXT_BOX_x):? i; 472 | 473 | input i1 474 | if i1<>"" then 475 | if mid(i1,1,2)="0x" then i1=mid(i1,3,len(i1)-2):i1 = "&H" + i1 476 | if mid(i1,1,1)="$" then i1=mid(i1,2,len(i1)-1):i1 = "&H" + i1 477 | z= val(i1) 478 | endif 479 | 480 | box(0) 481 | end sub 482 | 483 | 484 | Sub box( i as integer ) 485 | for y=0 to 10 486 | color_rg(i,TXT_BOX_y-1+y,TXT_BOX_x-1):?" "; 487 | next y 488 | end sub 489 | 490 | 'dim shared as string d_filename 491 | 'dim shared as integer d_membase, d_memsize 492 | 493 | Sub save_dialog() 494 | file_dialog("Save binary:",".bin") 495 | if d_filename<>"" then save_file(d_filename,d_membase,d_memsize) 496 | 497 | box(0) 498 | end sub 499 | Sub load_dialog() 500 | file_dialog("Load Binary:",".bin") 501 | if d_filename<>"" then load_file(d_filename,d_membase,d_memsize) 502 | 503 | box(0) 504 | end sub 505 | 506 | Sub save_mif() 507 | dim as integer mifpos 508 | file_dialog("Save a Quartus .mif (Memory Initialization File):",".mif") 509 | 510 | if d_filename<>"" then 511 | 512 | OPEN d_filename FOR OUTPUT AS #2 513 | PRINT #2, "-- Generated by BrianHG's RS232_Debugger hex editor." 514 | PRINT #2, "" 515 | PRINT #2, "WIDTH=8;" 516 | PRINT #2, "DEPTH=";d_memsize;";" 517 | PRINT #2, "" 518 | PRINT #2, "ADDRESS_RADIX=UNS;" 519 | PRINT #2, "DATA_RADIX=UNS;" 520 | PRINT #2, "" 521 | PRINT #2, "CONTENT BEGIN" 522 | 523 | for x=d_membase to d_membase+d_memsize-1 524 | 525 | ?#2, mifpos;" : ";read_buffer(x);";" 526 | 527 | mifpos=mifpos + 1 528 | next x 529 | 530 | PRINT #2, "END;" 531 | close #2 532 | 533 | end if 534 | 535 | box(0) 536 | end sub 537 | 538 | 539 | Sub save_mif16() 540 | dim as integer mifpos 541 | file_dialog("Save a Quartus .mif (Memory Initialization File):",".mif") 542 | 543 | if d_filename<>"" then 544 | 545 | OPEN d_filename FOR OUTPUT AS #2 546 | PRINT #2, "-- Generated by BrianHG's RS232_Debugger hex editor." 547 | PRINT #2, "" 548 | PRINT #2, "WIDTH=16;" 549 | PRINT #2, "DEPTH=";int(d_memsize/2);";" 550 | PRINT #2, "" 551 | PRINT #2, "ADDRESS_RADIX=UNS;" 552 | PRINT #2, "DATA_RADIX=UNS;" 553 | PRINT #2, "" 554 | PRINT #2, "CONTENT BEGIN" 555 | 556 | for x=d_membase to d_membase+int(d_memsize/2)-1 557 | 558 | if ENDIAN=1 then ?#2, mifpos;" : ";int(read_buffer(x*2+1)*256+read_buffer(x*2+0));";" 559 | if ENDIAN=0 then ?#2, mifpos;" : ";int(read_buffer(x*2+0)*256+read_buffer(x*2+1));";" 560 | 561 | mifpos=mifpos + 1 562 | next x 563 | 564 | PRINT #2, "END;" 565 | close #2 566 | 567 | end if 568 | box(0) 569 | end sub 570 | 571 | Sub save_mif32() 572 | dim as integer mifpos 573 | file_dialog("Save a Quartus .mif (Memory Initialization File):",".mif") 574 | 575 | if d_filename<>"" then 576 | 577 | OPEN d_filename FOR OUTPUT AS #2 578 | PRINT #2, "-- Generated by BrianHG's RS232_Debugger hex editor." 579 | PRINT #2, "" 580 | PRINT #2, "WIDTH=32;" 581 | PRINT #2, "DEPTH=";int(d_memsize/4);";" 582 | PRINT #2, "" 583 | PRINT #2, "ADDRESS_RADIX=UNS;" 584 | PRINT #2, "DATA_RADIX=UNS;" 585 | PRINT #2, "" 586 | PRINT #2, "CONTENT BEGIN" 587 | 588 | for x=d_membase to d_membase+int(d_memsize/4)-1 589 | 590 | if ENDIAN=1 then ?#2, mifpos;" : ";int(read_buffer(x*4+3)*16777216+read_buffer(x*4+2)*65536+read_buffer(x*4+1)*256+read_buffer(x*4+0));";" 591 | if ENDIAN=0 then ?#2, mifpos;" : ";int(read_buffer(x*4+0)*16777216+read_buffer(x*4+1)*65536+read_buffer(x*4+2)*256+read_buffer(x*4+3));";" 592 | 593 | mifpos=mifpos + 1 594 | next x 595 | 596 | PRINT #2, "END;" 597 | close #2 598 | 599 | end if 600 | box(0) 601 | end sub 602 | 603 | 604 | Sub file_dialog( i as string, fn as string ) 605 | dim as string i1,i2,i3 606 | dim as integer mst,mlen,errd,hexin 607 | box(7):z=0 608 | color_rg(7,TXT_BOX_y+0,TXT_BOX_x):? i; 609 | color_rg(7,TXT_BOX_y+1,TXT_BOX_x):? "Enter [filename],[addr start],[data length]:" 610 | color_rg(7,TXT_BOX_y+2,TXT_BOX_x):input i1,i2,i3 611 | hexin=0 612 | if mid(i2,1,2)="0x" then i2=mid(i2,3,len(i2)-2):i2 = "&H" + i2:hexin=1 613 | if mid(i2,1,1)="$" then i2=mid(i2,2,len(i2)-1):i2 = "&H" + i2:hexin=1 614 | if mid(i3,1,2)="0x" then i3=mid(i3,3,len(i3)-2):i3 = "&H" + i3 615 | if mid(i3,1,1)="$" then i3=mid(i3,2,len(i3)-1):i3 = "&H" + i3 616 | mst=val(i2):mlen=val(i3) 617 | 618 | if len(i1)>4 and mid(i1,len(i1)-3,1)<>"." then i1=i1+fn 619 | if len(i1)<>0 and len(i1)<5 then i1=i1+fn 620 | 621 | d_filename = "" 622 | d_membase = 0 623 | d_memsize = 0 624 | errd=0 625 | if mst >= MAX_MEM or mlen > MAX_MEM then errd=1 626 | if mlen=0 then mlen = MAX_MEM-mst 627 | if mst+mlen > MAX_MEM or errd=1 then errd=1:color_rg(2,TXT_BOX_y+5,TXT_BOX_x):?"Address out of range error.";:color_rg(2,TXT_BOX_y+6,TXT_BOX_x):?"Press any key to continue.";:sleep 628 | 629 | 630 | if i1<>"" and errd=0 then 631 | color_rg(7,TXT_BOX_y+4,TXT_BOX_x):? i;" ";i1;"." 632 | color_rg(7,TXT_BOX_y+5,TXT_BOX_x) 633 | if hexin = 1 then ?"from addr $";phex24(mst);" to $";phex24(mst+mlen-1);"."; 634 | if hexin = 0 then ?"from addr";mst;" to";mst+mlen-1;"."; 635 | 636 | 637 | color_rg(2,TXT_BOX_y+7,TXT_BOX_x):?"Proceede? [Y/N]" 638 | fn="":While (fn<>"Y" and fn<>"N" and fn<>chr(27) and fn<>chr(255)):fn=ucase(inkey):sleep 10,0:wend 639 | d_filename = "" 640 | if fn="Y" then d_filename=i1:d_membase=mst:d_memsize=mlen 641 | end if 642 | 643 | end sub 644 | 645 | 646 | 647 | Sub save_file(fname as string, start as integer, size as integer) 648 | color rgb(255,255,255),rgb(0,0,255) 649 | locate 60,32:? " SAVING > ";fname;" < "; 650 | color_rg(0,0,0) 651 | 652 | 'read_gpu_all(start,size) 653 | read_gpu_all(0,MAX_MEM) 654 | 655 | open fname For Binary Access Write As 2 656 | put #2,,read_buffer(start),size 657 | close #2 658 | end sub 659 | 660 | 661 | 662 | 663 | Sub load_file(fname as string, start as integer, size as integer) 664 | 665 | if size+start > MAX_MEM then size = MAX_MEM-start 666 | open fname For Binary Access Read As 2 667 | 668 | color rgb(255,255,255),rgb(0,0,255) 669 | locate 60,32:? " LOADING > ";fname;" < With";lof(2);" bytes."; 670 | color_rg(0,0,0) 671 | 672 | if lof(2)>0 then 673 | if lof(2)MAX_MEM then size=MAX_MEM-start 675 | if size>0 then get #2,,read_buffer(start),size 676 | end if 677 | 678 | 679 | if lof(2)<1 then 680 | box(2) 681 | color_rg(7,TXT_BOX_y+1,TXT_BOX_x):?" Cannot load file." 682 | color_rg(7,TXT_BOX_y+3,TXT_BOX_x):?" Press any key to continue." 683 | sleep 684 | box(0) 685 | end if 686 | 687 | close #2 688 | 689 | 690 | 'write_gpu_all(start,size) 691 | write_gpu_all(0,MAX_MEM) 692 | 693 | end sub 694 | 695 | 696 | ' ***************************************************** 697 | ' ******************* handle RS232 communications 698 | ' ***************************************************** 699 | ' ******************* Open and close com port 700 | ' ***************************************************** 701 | 702 | Sub open_com() 703 | 704 | close #1 705 | 706 | box(7) 707 | color_rg(7,TXT_BOX_y+0,TXT_BOX_x):? "Note that opening a valid com will replace the" 708 | color_rg(7,TXT_BOX_y+1,TXT_BOX_x):? "current memory on display with the contents of" 709 | color_rg(7,TXT_BOX_y+2,TXT_BOX_x):? "the RS232_Debugger hardware." 710 | color_rg(7,TXT_BOX_y+3,TXT_BOX_x):? "Press ";:color_rg(2,0,0):?"[ENTER]";:color_rg(7,0,0):?" to abort."; 711 | color_rg(7,TXT_BOX_y+5,TXT_BOX_x):? "Enter Com# ";:input com_num 712 | 713 | 714 | com_port="COM"+com_num+":921600,N,8,1,CS,DS,BIN,DT" 715 | 716 | 717 | if com_num<>"" then 718 | 719 | box(7) 720 | color_rg(7,TXT_BOX_y+0,TXT_BOX_x):? "Opening com:" 721 | color_rg(7,TXT_BOX_y+2,TXT_BOX_x):? com_port; 722 | 723 | OPEN COM com_port For Binary Access AS 1 724 | ?#1,chr(0); : rem Must tx at least 1 character 725 | in_port(4)=0:com_setport():in_port(4)=0:com_setport() : rem get ADDR size, 2 attempts 726 | end if 727 | 728 | if in_port(4)=0 and com_num<>"" then 729 | 730 | color_rg(2,TXT_BOX_y+4,TXT_BOX_x):? "Opening COM";com_num;" has not connected"; 731 | color_rg(2,TXT_BOX_y+5,TXT_BOX_x):? "to a RS232 Debugger peripheral."; 732 | color_rg(2,TXT_BOX_y+6,TXT_BOX_x):? "Entering COM debug state."; 733 | color_rg(2,TXT_BOX_y+8,TXT_BOX_x):? "Use CTRL-O / CTRL-C to change COM port."; 734 | rem com_num="" 735 | sleep 736 | rem close #1 737 | 738 | end if 739 | 740 | if com_num<>"" and in_port(4)>7 then 741 | MAX_MEM = 2^in_port(4) 742 | if MAX_MEM>MAX_MEM_ALLOC then MAX_MEM = MAX_MEM_ALLOC 743 | 744 | color_rg(7,TXT_BOX_y+4,TXT_BOX_x):? "Received RS232_Debugger address size of:"; 745 | color_rg(7,TXT_BOX_y+6,TXT_BOX_x):? in_port(4);" which =";MAX_MEM;" bytes of ram."; 746 | color_rg(7,TXT_BOX_y+8,TXT_BOX_x):? "Press any key to begin editing memory."; 747 | 748 | 749 | 750 | if MAX_MEM > MAX_MEM_ALLOC then MAX_MEM = MAX_MEM_ALLOC 751 | sleep 5000 752 | gpu_addr=0:read_gpu_all(0,MAX_MEM) 753 | 754 | end if 755 | 756 | print_setup() 757 | 758 | end sub 759 | 760 | 761 | Sub close_com() 762 | 763 | close #1 764 | box(7) 765 | color_rg(7,TXT_BOX_y+0,TXT_BOX_x):? "Closed COM";com_num;"."; 766 | color_rg(7,TXT_BOX_y+2,TXT_BOX_x):? "Press any key to enter file hex editor mode." 767 | color_rg(7,TXT_BOX_y+4,TXT_BOX_x):? "Use CTRL-O to open a new com port at any time." 768 | color_rg(7,TXT_BOX_y+6,TXT_BOX_x):? "Use CTRL-C to close the com port and enter" 769 | color_rg(7,TXT_BOX_y+7,TXT_BOX_x):? " file hext editor mode." 770 | 771 | 772 | com_num="" 773 | MAX_MEM = MAX_MEM_ALLOC 774 | gpu_addr=0 775 | sleep 4000 776 | print_setup() 777 | 778 | end sub 779 | 780 | ' ***************************************************** 781 | ' ******************* handle RS232 communications 782 | ' ***************************************************** 783 | ' ******************* Read and Write All 784 | ' ***************************************************** 785 | 786 | Sub read_gpu_all(mbase as integer, msize as integer) 787 | 788 | if msize > COM_CACHE then 789 | for mpos=mbase to msize-1 step COM_CACHE 790 | read_gpu(mpos,COM_CACHE) 791 | next mpos 792 | end if 793 | 794 | if msize <= COM_CACHE then read_gpu(mpos,msize) 795 | 796 | end sub 797 | 798 | Sub write_gpu_all(mbase as integer, msize as integer) 799 | 800 | if msize > COM_CACHE then 801 | for mpos=mbase to msize-1 step COM_CACHE 802 | write_gpu(mpos,COM_CACHE) 803 | next mpos 804 | end if 805 | 806 | if msize <= COM_CACHE then write_gpu(mpos,msize) 807 | 808 | 809 | end sub 810 | 811 | 812 | ' ***************************************************** 813 | ' ******************* handle RS232 communications 814 | ' ***************************************************** 815 | ' ******************* READ 816 | ' ***************************************************** 817 | 818 | Sub read_gpu(mbase as integer, msize as integer) 819 | if com_num<>"" then 820 | 821 | y=45:if COM_VERBOSE=1 then for x=0 to 3:color_rg(0,x+y,1):? " ",,:next x 822 | com_rxp=com_rxp+1:com_rxp=com_rxp and 8191 823 | color_rg(1,y,1):?" Com read #" ;px9999(com_rxp);" Address $";phex24(mbase);" with ";px9999(msize);" bytes. "; 824 | 825 | ?#1,cmd_null16; 826 | if COM_FLUSH=1 then 827 | if COM_VERBOSE=1 then color_rg(1,y+1,1):?" Flushing GPU. "; 828 | for x=0 to 16 829 | ?#1,cmd_null16; 830 | next x 831 | endif 832 | 833 | com_timer = timer*100 + COM_PRE_TIMEOUT 834 | if COM_WAIT=1 and COM_PRE_TIMEOUT>0 then 835 | if COM_VERBOSE=1 then color_rg(1,y+1,1):?" Waiting for flush. "; 836 | while (loc(1)>0 or com_timer>timer*100 ) 837 | if loc(1)>0 then get #1,,com_buffer(0),1:com_timer = timer*100 + COM_PRE_TIMEOUT 838 | wend 839 | end if 840 | 841 | 842 | if msize < 256 then 843 | stemp = chr(int(mbase/65536) and 255) + chr(int(mbase/256) and 255) + chr(mbase and 255) + chr(msize-1) 844 | stemp = cmd_read + stemp 845 | end if 846 | if msize >255 then 847 | stemp = chr(int(mbase/65536) and 255) + chr(int(mbase/256) and 255) + chr(mbase and 255) + chr(int(msize/256)-1) 848 | stemp = cmd_read_page + stemp 849 | end if 850 | 851 | 852 | if COM_VERBOSE=1 then color_rg(1,y+2,1):?" Sending read command. "; 853 | ?#1,cmd_prefix;stemp;stemp; 854 | 855 | 856 | com_timer = timer*100 + COM_POST_TIMEOUT 857 | if COM_VERBOSE=1 then color_rg(1,y+3,1):?" Waiting for response. "; 858 | while (loc(1)timer*100 ) 859 | sleep 1,0 860 | wend 861 | 862 | 863 | z=loc(1) 864 | if z0 ) 867 | get #1,,com_buffer(0),1 868 | wend 869 | end if 870 | 871 | if z>msize then 872 | color_rg(2,y+3,1):?" Error, read #";px9999(com_rxp);" received";px9999(loc(1));" bytes of ";px9999(msize);". "; 873 | While ( loc(1)>0 ) 874 | get #1,,com_buffer(0),1 875 | wend 876 | end if 877 | 878 | if z=msize then 879 | get #1,,read_buffer(mbase),z 880 | if COM_VERBOSE=1 then color_rg(1,y+3,1):?" Read #";px9999(com_rxp);" was successfull. "; 881 | endif 882 | 883 | 884 | 885 | end if 886 | end sub 887 | 888 | 889 | 890 | ' ***************************************************** 891 | ' ******************* handle RS232 communications 892 | ' ***************************************************** 893 | ' ******************* WRITE 894 | ' ***************************************************** 895 | 896 | Sub write_gpu(mbase as integer, msize as integer) 897 | if com_num<>"" then 898 | 899 | 900 | y=45:if COM_VERBOSE=1 then for x=0 to 3:color_rg(0,x+y,1):? " ",,:next x 901 | com_txp=com_txp+1:com_txp=com_txp and 8191 902 | color_rg(2,y,1):?" Com write #" ;px9999(com_txp);" Address $";phex24(mbase);" with";px9999(msize);" bytes. "; 903 | 904 | ?#1,cmd_null16; 905 | if COM_FLUSH=1 then 906 | if COM_VERBOSE=1 then color_rg(1,y+1,1):?" Flushing GPU. "; 907 | for x=0 to 16 908 | ?#1,cmd_null16; 909 | next x 910 | endif 911 | 912 | com_timer = timer*100 + COM_PRE_TIMEOUT 913 | if COM_WAIT=1 and COM_PRE_TIMEOUT>0 then 914 | if COM_VERBOSE=1 then color_rg(1,y+1,1):?" Waiting for flush. "; 915 | while (loc(1)>0 or com_timer>timer*100 ) 916 | if loc(1)>0 then get #1,,com_buffer(0),1:com_timer = timer*100 + COM_PRE_TIMEOUT 917 | wend 918 | end if 919 | 920 | 921 | if msize < 256 then 922 | stemp = chr(int(mbase/65536) and 255) + chr(int(mbase/256) and 255) + chr(mbase and 255) + chr(msize-1) 923 | stemp = cmd_write + stemp 924 | end if 925 | if msize >255 then 926 | stemp = chr(int(mbase/65536) and 255) + chr(int(mbase/256) and 255) + chr(mbase and 255) + chr(int(msize/256)-1) 927 | stemp = cmd_write_page + stemp 928 | end if 929 | 930 | 931 | if COM_VERBOSE=1 then color_rg(1,y+2,1):?" Sending write command. "; 932 | ?#1,cmd_prefix;stemp;stemp; 933 | 934 | if COM_VERBOSE=1 then color_rg(1,y+2,1):?" Sending write data. "; 935 | put #1,,read_buffer(mbase),msize 936 | 937 | 938 | com_timer = timer*100 + COM_POST_TIMEOUT 939 | if COM_VERBOSE=1 then color_rg(1,y+3,1):?" Waiting for write data echo. "; 940 | while (loc(1)timer*100 ) 941 | wend 942 | 943 | 944 | z=loc(1) 945 | if z0 ) 948 | get #1,,com_buffer(0),1 949 | wend 950 | end if 951 | 952 | if z>msize then 953 | color_rg(2,y+3,1):?" Error, write #";px9999(com_txp);" verify received ";px9999(loc(1));" bytes of ";px9999(msize);". "; 954 | While ( loc(1)>0 ) 955 | get #1,,com_buffer(0),1 956 | wend 957 | end if 958 | 959 | if z=msize then 960 | get #1,,verify_buffer(0),z 961 | c=1 962 | 963 | for x=0 to z-1 964 | if read_buffer(mbase+x)<>verify_buffer(x) then c=0 965 | next x 966 | 967 | if COM_VERBOSE=1 then if c=1 then color_rg(1,y+3,1):?" Write #";px9999(com_txp);" was confirmed. "; 968 | if c=0 then color_rg(2,y+3,1):?" Write #";px9999(com_txp);" verify has data errors. ";:if COM_VERBOSE=1 then show_errors(mbase) 969 | 970 | 971 | end if 972 | end if 973 | end sub 974 | 975 | sub show_errors(q as integer) 976 | for y=0 to 15 977 | for x=0 to 15 978 | c=1 979 | if read_buffer(q+x+y*16)<>verify_buffer(x+y*16) then c=2 980 | color_rg(c, y*2+5+1, x*3+7 ):? " ";phex8(verify_buffer(x+y*16));" "; 981 | next x 982 | next y 983 | end sub 984 | 985 | 986 | 987 | 988 | ' ***************************************************************** 989 | ' ******************* handle RS232 communications 990 | ' ***************************************************************** 991 | ' ******************* Set Out0,1,2,3, Read In0,1,2,3,ADDR_SIZE 992 | ' ***************************************************************** 993 | 994 | Sub com_setport() 995 | dim as integer msize 996 | msize = 5 997 | 998 | if com_num<>"" then 999 | 1000 | y=47:if COM_VERBOSE=1 then for x=0 to 3:color_rg(0,x+y,1):? " ",:next x 1001 | com_sxp=com_sxp+1:com_sxp=com_sxp and 8191 1002 | if COM_VERBOSE=1 then color_rg(1,y,1):?" Com Setport #" ;px9999(com_sxp);". "; 1003 | 1004 | ?#1,cmd_null16; 1005 | if COM_FLUSH=1 then 1006 | if COM_VERBOSE=1 then color_rg(1,y+1,1):?" Flushing COM. "; 1007 | for x=0 to 16 1008 | ?#1,cmd_null16; 1009 | next x 1010 | endif 1011 | 1012 | com_timer = timer*100 + COM_PRE_TIMEOUT 1013 | if COM_WAIT=1 and COM_PRE_TIMEOUT>0 then 1014 | if COM_VERBOSE=1 then color_rg(1,y+1,1):?" Waiting for flush. "; 1015 | while (loc(1)>0 or com_timer>timer*100 ) 1016 | if loc(1)>0 then get #1,,com_buffer(0),1:com_timer = timer*100 + COM_PRE_TIMEOUT 1017 | wend 1018 | end if 1019 | 1020 | 1021 | stemp = chr(out_port(0)) + chr(out_port(1)) + chr(out_port(2)) + chr(out_port(3)) 1022 | stemp = cmd_setp + stemp 1023 | 1024 | if COM_VERBOSE=1 then color_rg(1,y+1,1):?" Sending Set Port Command. "; 1025 | ?#1,cmd_prefix;stemp;stemp; 1026 | 1027 | 1028 | com_timer = timer*100 + COM_POST_TIMEOUT 1029 | if COM_VERBOSE=1 then color_rg(1,y+2,1):?" Waiting for response. "; 1030 | while (loc(1)timer*100 ) 1031 | sleep 1,0 1032 | wend 1033 | 1034 | 1035 | z=loc(1) 1036 | if z0 ) 1039 | get #1,,com_buffer(0),1 1040 | wend 1041 | end if 1042 | 1043 | if z>msize then 1044 | color_rg(2,y+2,1):?" Error, read #";px9999(com_sxp);". Received";px9999(loc(1));" bytes of ";px9999(msize);"."; 1045 | While ( loc(1)>0 ) 1046 | get #1,,com_buffer(0),1 1047 | wend 1048 | end if 1049 | 1050 | if z=msize then 1051 | get #1,,in_port(0),z 1052 | if COM_VERBOSE=1 then color_rg(1,y+2,1):?" Setport #";px9999(com_sxp);" was successfull."; 1053 | endif 1054 | 1055 | 1056 | 1057 | end if 1058 | end sub 1059 | 1060 | 1061 | ' ***************************************************** 1062 | ' ******************* End of handle RS232 communications 1063 | ' ***************************************************** 1064 | 1065 | 1066 | 1067 | 1068 | sub put_undo() 1069 | undobase=gpu_addr 1070 | for x=0 to 255 1071 | undo_buffer(x)=read_buffer(x+gpu_addr) 1072 | next x 1073 | end sub 1074 | 1075 | sub get_undo() 1076 | for x=0 to 255 1077 | read_buffer(x+undobase)=undo_buffer(x) 1078 | next x 1079 | print_dec() 1080 | end sub 1081 | 1082 | 1083 | 1084 | 1085 | sub hex_enter() 1086 | z=-1 1087 | c=asc(ink) 1088 | if c>=48 and c<=57 then z=c-48 1089 | if c>=asc("a") and c<=asc("f") then z=c-asc("a")+10 1090 | 1091 | if z<>-1 and hp=0 then read_buffer(mcz)=(read_buffer(mcz) and 15) + z*16:hp=1 1092 | if z<>-1 and hp=2 then read_buffer(mcz)=(read_buffer(mcz) and 240) + z 1093 | 1094 | print_dec() 1095 | 1096 | if hp=2 then hp=0:inc_cursor(1,0) 1097 | if hp=1 then hp=2 1098 | 1099 | end sub 1100 | 1101 | 1102 | 1103 | sub ascii_enter() 1104 | read_buffer(mcz) = asc(ink) 1105 | print_dec() 1106 | inc_cursor(1,0) 1107 | print_dec() 1108 | end sub 1109 | 1110 | 1111 | sub inc_cursor(xofs as byte, yofs as byte) 1112 | mcx1=mcx1+xofs 1113 | mcy1=mcy1+yofs 1114 | if mcx1>15 then mcx1=0:mcy1=mcy1+1 1115 | if mcx1<0 then mcx1=15:mcy1=mcy1-1 1116 | 1117 | if mcy1>15 then mcy1=mcy1-1:if xofs=1 then mcx1=15:REM UNDO BUFFER BUG gpu_addr=gpu_addr+16:if gpu_addr>(MAX_MEM-256) then gpu_addr=(MAX_MEM-256) Rem rend of screen 1118 | if mcy1<0 then mcy1=mcy1+1:if xofs=-1 then mcx1=0 1119 | 1120 | mcz=gpu_addr+mcy1*16+mcx1 1121 | print_dec() 1122 | end sub 1123 | 1124 | 1125 | 1126 | sub print_hex() 1127 | 1128 | c=1:if edit_mode=1 and edit_pos=0 then c=2 1129 | color_rg(c, 3 , 1 ):? " HEX +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F ":? " "; 1130 | 1131 | for y=0 to 15 1132 | z=gpu_addr+y*16:gpu_printadr() 1133 | for x=0 to 15 1134 | locate y*2+5,x*3+7:? " ";phex8(read_buffer(z+x));" "; 1135 | next x 1136 | 1137 | for x=0 to 15 1138 | locate y*2+5,x*2+57:? " "; 1139 | locate y*2+5,x*2+57:? " ";asc_str(read_buffer(z+x)); 1140 | next x 1141 | 1142 | next y 1143 | 1144 | c=1:if edit_mode=1 and edit_pos=1 then c=2 1145 | color_rg(c, 3 , 57 ):? " ASCII "; 1146 | for y=3 to 36:locate y,90:?" "; 1147 | next y 1148 | color_rg(0,0,0) 1149 | 1150 | end sub 1151 | 1152 | sub gpu_printadr() 1153 | color_rg(c, y*2+5 , 1 ):? phex24(z) 1154 | ? " "; 1155 | color_rg(0,0,0) 1156 | end sub 1157 | 1158 | 1159 | 1160 | 1161 | 1162 | 1163 | sub print_mouse() 1164 | 1165 | const ADDRhy = 38 1166 | const ADDRdy = 40 1167 | const ADDRx1 = 1 1168 | const ADDRx2 = 24 1169 | const datbiny = 38 1170 | const datdec8y = 40 1171 | const datdec16y = 42 1172 | const datdecx1 = 27 1173 | const datdecx2 = 46 1174 | const datbin2 = 58 1175 | const datbinx128 = 43 1176 | const datbinx64 = 45 1177 | const datbinx32 = 47 1178 | const datbinx16 = 49 1179 | const datbinx8 = 51 1180 | const datbinx4 = 53 1181 | const datbinx2 = 55 1182 | const datbinx1 = 57 1183 | 1184 | edit_col=0 1185 | 1186 | if edit_mode = 0 then 1187 | 1188 | m2cx = (mx+4)/8 1189 | m2cy = (my+4)/8 1190 | if m2cy = ADDRhy and m2cx >= ADDRx1 and m2cx <= ADDRx2 then edit_col = 1 1191 | if m2cy = ADDRdy and m2cx >= ADDRx1 and m2cx <= ADDRx2 then edit_col = 2 1192 | if edit_col=1 and mb=1 then inputhex("Enter new hex address:"):if z>0 then gpu_addr=z and 1048560 1193 | if edit_col=2 and mb=1 then inputdec("Enter new decimal address:"):if z>0 then gpu_addr=z and 1048560 1194 | 1195 | 1196 | if mx<450 then 1197 | 1198 | mcx = (mx-64)/24 1199 | mcy = (my-34)/16 1200 | 1201 | if mcx>=0 and mcx<16 and mcy>=0 and mcy<16 then 1202 | 1203 | mcx1=mcx:mcy1=mcy 1204 | mcz=gpu_addr+mcy1*16+mcx1 1205 | 1206 | if mb = 1 then edit_mode=1:edit_pos=0:put_undo() 1207 | 1208 | 1209 | end if 1210 | end if 1211 | 1212 | 1213 | if mx>450 then 1214 | 1215 | mcx = (mx-459)/16 1216 | mcy = (my-34)/16 1217 | 1218 | if mcx>=0 and mcx<16 and mcy>=0 and mcy<16 then 1219 | 1220 | mcx1=mcx:mcy1=mcy 1221 | mcz=gpu_addr+mcy1*16+mcx1 1222 | 1223 | if mb = 1 then edit_mode=1:edit_pos=1:put_undo() 1224 | 1225 | end if 1226 | end if 1227 | end if :rem EDIT mode 0 1228 | 1229 | 1230 | if edit_mode = 1 then 1231 | 1232 | 1233 | m2cx = (mx+4)/8 1234 | m2cy = (my+4)/8 1235 | 'locate m2cy,m2cx:? m2cx; 1236 | 1237 | if m2cy = datbiny and m2cx >= datdecx1 and m2cx <= datbin2 then edit_col = 3 1238 | if m2cy = datdec8y and m2cx >= datdecx1 and m2cx <= datdecx2 then edit_col = 4 1239 | if m2cy = datdec16y and m2cx >= datdecx1 and m2cx <= datdecx2 then edit_col = 5 1240 | 1241 | if edit_col=4 and mb=1 then inputdec("Enter new data byte:"):if z>0 then read_buffer(mcz)=z and 255 1242 | if edit_col=5 and mb=1 then inputdec("Enter new data for 16bit byte:"):if z>0 then z=z and 65535:read_buffer(int(mcz/2)*2)=int(z/256):read_buffer(int(mcz/2)*2+1)=z and 255 1243 | 1244 | 1245 | 1246 | 1247 | if m2cx = datbinx128 and edit_col=3 and mbl=0 and mb=1 then read_buffer(mcz)=read_buffer(mcz) xor 128 1248 | if m2cx = datbinx64 and edit_col=3 and mbl=0 and mb=1 then read_buffer(mcz)=read_buffer(mcz) xor 64 1249 | if m2cx = datbinx32 and edit_col=3 and mbl=0 and mb=1 then read_buffer(mcz)=read_buffer(mcz) xor 32 1250 | if m2cx = datbinx16 and edit_col=3 and mbl=0 and mb=1 then read_buffer(mcz)=read_buffer(mcz) xor 16 1251 | if m2cx = datbinx8 and edit_col=3 and mbl=0 and mb=1 then read_buffer(mcz)=read_buffer(mcz) xor 8 1252 | if m2cx = datbinx4 and edit_col=3 and mbl=0 and mb=1 then read_buffer(mcz)=read_buffer(mcz) xor 4 1253 | if m2cx = datbinx2 and edit_col=3 and mbl=0 and mb=1 then read_buffer(mcz)=read_buffer(mcz) xor 2 1254 | if m2cx = datbinx1 and edit_col=3 and mbl=0 and mb=1 then read_buffer(mcz)=read_buffer(mcz) xor 1 1255 | 1256 | end if : rem edit mode 1 1257 | 1258 | if mx<>-1 then print_dec() 1259 | 1260 | end sub 1261 | 1262 | 1263 | 1264 | sub click_binary(xp as integer, yp as integer, eb as Ubyte) 1265 | 1266 | m2cx = (mx+4)/8 1267 | m2cy = (my+4)/8 1268 | 'locate m2cy,m2cx:? m2cx;m2cy; 1269 | 1270 | if m2cy=yp and m2cx+2 > xp and m2cx-16 < xp then 1271 | color_rg(7,yp,xp-1):? bin_str(out_port(eb)); 1272 | out_port(eb)=out_port(eb) + mwd 1273 | if m2cx = (xp + 0 ) and mbl=0 and mb=1 then out_port(eb)=out_port(eb) xor 128 1274 | if m2cx = (xp + 2 ) and mbl=0 and mb=1 then out_port(eb)=out_port(eb) xor 64 1275 | if m2cx = (xp + 4 ) and mbl=0 and mb=1 then out_port(eb)=out_port(eb) xor 32 1276 | if m2cx = (xp + 6 ) and mbl=0 and mb=1 then out_port(eb)=out_port(eb) xor 16 1277 | if m2cx = (xp + 8 ) and mbl=0 and mb=1 then out_port(eb)=out_port(eb) xor 8 1278 | if m2cx = (xp + 10) and mbl=0 and mb=1 then out_port(eb)=out_port(eb) xor 4 1279 | if m2cx = (xp + 12) and mbl=0 and mb=1 then out_port(eb)=out_port(eb) xor 2 1280 | if m2cx = (xp + 14) and mbl=0 and mb=1 then out_port(eb)=out_port(eb) xor 1 1281 | end if 1282 | 1283 | end sub 1284 | 1285 | 1286 | 1287 | 1288 | sub print_dec() 1289 | 1290 | color_rg(0, mcy1*2+5, mcx1*2+57):? ">"; 1291 | color_rg(4, 0 , 0 ):? asc_str(read_buffer(mcz)); 1292 | color_rg(5, mcy1*2+5, mcx1*3+7 ):? " ";phex8(read_buffer(mcz));" "; 1293 | 1294 | 1295 | z=3:if edit_col=1 then z=7 1296 | color_rg(z, 38 , 1 ):? "Address Hex :"; 1297 | z=0:if edit_col=1 then z=7 1298 | color_rg(z, 0 , 0 ):? " ";phex24(mcz); " "; 1299 | 1300 | z=3:if edit_col=2 then z=7 1301 | color_rg(z, 40 , 1 ):? "Address Decimal :"; 1302 | z=0:if edit_col=2 then z=7 1303 | color_rg(z, 0 , 0 ):? mcz, 1304 | 1305 | 1306 | z=3:if edit_col=3 then z=7 1307 | color_rg(z, 38 , 27 ):? "Binary :"; 1308 | z=0:if edit_col=3 then z=7 1309 | color_rg(z, 0 , 0 ):? bin_str(read_buffer(mcz)); 1310 | 1311 | 1312 | z=3:if edit_col=4 then z=7 1313 | color_rg(z, 40 , 27 ):? "Decimal :"; 1314 | z=0:if edit_col=4 then z=7 1315 | color_rg(z, 0 , 0 ):? " ";read_buffer(mcz);" "; 1316 | 1317 | z=3:if edit_col=5 then z=7 1318 | color_rg(z, 42 , 27 ):? "16bit Decimal :"; 1319 | if ENDIAN=1 then y = read_buffer(int(mcz/2)*2+0)*256 + read_buffer(int(mcz/2)*2+1) 1320 | if ENDIAN=0 then y = read_buffer(int(mcz/2)*2+1)*256 + read_buffer(int(mcz/2)*2+0) 1321 | z=0:if edit_col=5 then z=7 1322 | color_rg(z, 0 , 0 ):? y;" "; 1323 | 1324 | end sub 1325 | 1326 | 1327 | sub color_rg( colm as ubyte, yp as ubyte, xp as ubyte ) 1328 | 1329 | if xp<>0 and yp<>0 then locate yp,xp 1330 | 1331 | if colm=0 then color rgb(224,224,224),rgb(0,0,0) : REM white text 1332 | 1333 | if colm=1 then color rgb(255,255,255),rgb(32,96,0) : REM Green outline 1334 | if colm=2 then color rgb(255,255,255),rgb(128,16,0) : REM Red outline 1335 | 1336 | if colm=3 then color rgb(0,0,0),rgb(224,224,224) : REM Negative white 1337 | if colm=4 then color rgb(0,0,0),rgb(255,255,255) : REM Negative white X-bright 1338 | 1339 | if colm=5 then color rgb(192,255,255),rgb(96,48,16) : REM Blue on dark red 1340 | 1341 | if colm=6 then color rgb(192,255,255),rgb(0,224,224) : REM Blue on green 1342 | if colm=7 then color rgb(255,255,64),rgb(0,0,128) : REM Blue on red 1343 | 1344 | 1345 | end sub 1346 | --------------------------------------------------------------------------------