Meditation, The Art of Exploitation

Thinking? At last I have discovered it--thought; this alone is inseparable from me. I am, I exist--that is certain. But for how long? For as long as I am thinking. For it could be, that were I totally to cease from thinking, I should totally cease to exist....I am, then, in the strict sense only a thing that thinks.

Monday, April 07, 2008

FPGA: LCD display from RS232 interface

After more than a month's of studying of verilog and fpga design, I am proud to present the result of my first mini-project. Controlling Spartan3A LCD display with RS232 serial interface from a host computer. The setup is very simple:


minicom (linux host) <------> RS232 (J27) <-------> LCD (DISP1)


I used the 2 serial interface modules from fpga4fun.com (async_receiver and async_transmitter). I implemented the main serial to lcd control module and the lcd display module. The lcd display module implementation is especially gratifying after it was completed. I learnt a great deal about finite state machine implementation in verilog and how sequential/combinatorial logic work together. Here is the state machine of the lcd controller (drawn using qfsm):



As you can see, state 2,3,4,5 (I didn't use one-hot encoding) all require that certain signal lines driven at a certain value for a certain amount of time (or number of clks). To achieve such kind of effect, one need to combine a FSM with a counter. The technical details of the requirements can be found in Spartan3A revion D's user's guide (ug334.pdf) in the LCD section.

The implementation of the lcd controller follows:


module lcd_controller (clk, rst_n, data_ready, rx_data, lcd_rs, lcd_rw, lcd_e, lcd_4, lcd_5, lcd_6, lcd_7);

parameter k = 18;
// in register_input mode, the input doesn't have to stay valid
// while the character is being transmitted
parameter register_input = 1;
parameter clr = 8'h0A;

input clk; // synthesis attribute PERIOD clk "50 MHz"
input rst_n;
input data_ready;
input [7:0] rx_data;
output lcd_rs;
output lcd_rw;
output lcd_e;
output lcd_7;
output lcd_6;
output lcd_5;
output lcd_4;

reg lcd_e, lcd_rs, lcd_rw, lcd_7, lcd_6, lcd_5, lcd_4;

reg [k+8:0] count;
reg [6:0] lcd_code;
reg [2:0] state;
reg [2:0] next_state;

wire lcd_ready = (state==1);

// store rx_data locally
reg [7:0] lcd_dataReg;
always @(posedge clk) if(data_ready & lcd_ready) lcd_dataReg <= rx_data;
wire [7:0] lcd_dataD = register_input ? lcd_dataReg : rx_data;

// continuous assignment by default of wire type, clr key clears display
wire clear = (rx_data == clr)? 1:0;
//assign {lcd_e,lcd_rs,lcd_rw,lcd_7,lcd_6,lcd_5,lcd_4} = lcd_code;

// sequential logic
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n)
begin
state <= 0;
next_state <= 0;
count <= 0;
lcd_code[6:0] <= 0;
end
else
state <= next_state;
end

always @ (posedge clk)
begin
case (state)
3'b000: count <= count + 1;
3'b001: count <= 0;
3'b010: count <= (count[4]? 0 : count + 1);
3'b011: count <= (count[5]? 0 : count + 1);
3'b100: count <= (count[4]? 0 : count + 1);
3'b101: count <= (count[10]? 0 : count + 1);
3'b110: count <= count + 1;
endcase
{lcd_e,lcd_rs,lcd_rw,lcd_7,lcd_6,lcd_5,lcd_4} <= lcd_code;
if(state == 0 || state == 6) lcd_e <= ^count[k+1:k];
end // sequential logic

// combinatorial logic
always @ (state or count or data_ready or clear) begin
case(state)
3'b000:
begin
if(count[k+5:k+2] == 12)
next_state = 3'b1; // idle_data/1
else
next_state = 0;
end
3'b001:
begin
if(data_ready) begin
if(clear)
next_state = 3'b110; // clear/6
else
next_state = 3'b10; // disp_hn/2
end
else
next_state = 3'b1; // idle_data/1
end
3'b010:
begin
if(count[4])
next_state = 3'b11; // idle_high/3
else
next_state = 3'b10; // disp_hn/3
end
3'b011:
begin
if(count[5])
next_state = 3'b100; // disp_ln/4
else
next_state = 3'b11; // idle_high/3
end
3'b100:
begin
if(count[4])
next_state = 3'b101; // wait/5
else
next_state = 3'b100; // disp_ln/4
end
3'b101:
begin
if(count[10])
next_state = 3'b1; // idle_data/1
else
next_state = 3'b101; // wait/5
end
3'b110:
begin
if(count[k+3:k+2] == 2)
next_state = 3'h1; // idle_data/1
else
next_state = 3'h6; // clear/6
end
endcase
end // combinatorial logic

// output logic
always @(state or count or lcd_dataD) begin
lcd_code <= 7'h00;
case(state)
3'b000:
begin
case (count[k+5:k+2])
0: lcd_code <= 7'h43; // power-on initialization
1: lcd_code <= 7'h43;
2: lcd_code <= 7'h43;
3: lcd_code <= 7'h42;
4: lcd_code <= 7'h42; // function set
5: lcd_code <= 7'h48;
6: lcd_code <= 7'h40; // entry mode set
7: lcd_code <= 7'h46;
8: lcd_code <= 7'h40; // display on/off control
9: lcd_code <= 7'h4C;
10: lcd_code <= 7'h40; // display clear
11: lcd_code <= 7'h41;
endcase
end
3'b001:
lcd_code <= 7'h00;
3'b010:
lcd_code <= {3'b110, lcd_dataD[7:4]};
3'b011:
lcd_code <= 7'b0110000;
3'b100:
lcd_code <= {3'b110, lcd_dataD[3:0]};
3'b101:
lcd_code <= 7'b0110000;
3'b110:
begin
case(count[k+2])
0: lcd_code <= 7'h40; // display clear
1: lcd_code <= 7'h41;
endcase
end
endcase
end // output logic

endmodule



Tuesday, April 01, 2008

Linux Networking 3: network bridge and bump in the wire

A Linux network bridge can be understood as a bump in the wire on steroid. In the physical world, a bridge is used to connect multiple landmass together. This notion is used in a similar meaning in networking. A Linux network bridge is virtual and it connects different 'Ethernet' network segments together, albeit transparently to the Ethernet packets going through it.

Ever wondered what the 'Bridged' networking means in VMWare? It's exactly the kind of network setup allowed by Linux network bridge (practically handled by bridge-utils). Except that VMWare has its own implementation of a virtual network bridge that connects the guest virtual network and the host network together, thus allowing the guest OS virtual network direct access to the external (relative to the host) network.

Because bridge works at Layer 2 for Ethernet packets, a bridge can often be considered functionally equivalent to a switch, albeit a virtual software solution. The simplest bridge acts as a bump in the wire, connecting different network segments just like a switch. However, bridge has the following distinctive advantages:

1) A bridge can act as a network interface and assume a binding IP address, allowing network access to the Linux host.

2) Network packets going through a bridge can be manipulated by iptables, thus allowing greater control such as mangling and filtering not present in switch and bump in the wire.

Because a virtual bridge only examines Ethernet header (layer 2), it's transparent to IP protocols . This has some implications:

1) It's important to take care of ARP tables that translate Ethernet address to IP address, no arp poisoning or other monkey business. The Linux host must forward arp packets properly.

2) It's important to avoid routing loops (cyclic routes through bridges), often requiring turning Spanning Tree Protocol (STP) in network bridges.

A bridge is most useful in the following scenarios:

1) Network transparency and redundancy is required for internal network users. Redundant virtual network bridges can be set up (use STP if necessary) to allow non-interrupted network traffic flow.

2) Administrator needs better packet filtering control over packets striding over network segments.

3) Simply replacing a hardware switch or act as a bump in the wire (connecting two hosts on same network for example)

References:
1) http://www.linux-foundation.org/en/Net:Bridge
2) http://www.vmweekly.com/articles/networking_in_vmware/1/