Silicon Chip – April 2019

(Ben Green) #1

siliconchip.com.au Australia’s electronics magazine April 2019 65


Here, the ternary operator (? :) as-
signs the “out” register the value of 1
(high) if the value of “count” is less
than “stop” and equal to or greater
than “start”. Otherwise, “out” is as-
signed the value 0 (low).
This could pass for valid C code,
apart from the ‘assign’ keyword, but
it should be remembered that we are
synthesising hardware in the form of
logic gates rather than compiling ma-
chine code.
At a few places in this project, we
want to increment a counter based on
an input, for example:


reg [9:0] counter = 0;
always @(posedge clk)
begin
counter <= (counter ==
div - 1)? 0 : counter + 1;
clkout <= (counter <
div/2)? 1 : 0;
end

This code is in the block that divides
the pixel clock down to a line clock.
The first line specifies that “counter”
is a 10-bit register, and is set to zero
on power-up.
The second line indicates that the
following sequence will only occur on
the positive edge of the “clk” signal.
The resulting synthesis will use flip-
flops to retain the state of the registers
between “clk” pulses.
The begin/end statements are used
to group the two following lines so
that they both occur inside the ‘al-
ways’ block.
Here, “counter” is incremented (ie,
its value is increased by one), unless it
has reached one less than the value of
“div”, in which case it is reset to zero.
Thus, “counter” counts from zero
to div-1, which gives us our horizon-
tal pixel position in the “counter”
register.
The “clkout” register is set to one
while “counter” is in the bottom half
of its cycle (less than div/2), and zero
when it is in the top half, thus divid-
ing the incoming “clk” signal by the
ratio of “div”.
This “clkout” signal is fed into an-
other similar code block, so that every
time the horizontal counter reaches
zero, the vertical counter is increment-
ed. This is how our raster is generated.
You might note that these registers
are loaded with a “<=” symbol instead
of a “=”.
The “<=” means that they are non-
blocking assignments, so they are con-


sidered to occur simultaneously.
If a specific order of assignment is
needed, then the “=” blocking assign-
ment operator can be used to enforce
this, particularly if the result of one
expression depends on the result of a
previous expression.
The memory block demonstrates a
few other features of Verilog. Using this
specific form of assignment is needed
to enforce the use of block RAM, as
mentioned earlier:
reg [7:0] mem [511:0];

always @(posedge wclk) begin
if (write_en)
mem[waddr] <= din;
end

always @(posedge rclk) begin
dout <= mem[raddr];
end

initial begin
if (MEM)
$readmemh(MEM,mem);
end

The first line defines an internal reg-
ister file “mem”, which has 512 (511-
0) eight-bit (7-0) elements, effectively,
an array. The first “always” block is re-
sponsible for writing to the memory,
where the 8-bit value “din” is stored
at position “waddr” in “mem” on the
positive edge of “wclk”, but only if
“write_en” is high (one).
The second “always” block per-
forms a read, loading the value of
the memory (mem) at “raddr” to the
“dout” register on the rising edge of
“rclk”. Block RAM is always synchro-
nous (requiring a clock) on the iCEs-
tick’s iCE40HX-1k.

Changing the baud rate
We suggested earlier that some of
the features such as baud rate, graph-
ics and colours can easily be modified.
The baud rate is controlled by a single
value within the UART block.
Around line 26 inside the UART
block is the definition of the CLOCK_
DIVIDE parameter.
You can select 115200 baud by
commenting (adding ‘//’ to the start
of) this line:
parameter CLOCK_DIVIDE = 312;

and removing the ‘//’ from the start
of
//parameter CLOCK_DIVIDE = 26;
SC

Note that the CLOCK_DIVIDE value
is determined by dividing 12,000,000
by four times the baud rate (or
3,000,000 divided by the baud rate)
and choosing the next lower integer.
Choosing the next lower integer
means the baud rate is slightly faster
than desired, but this will handle re-
ceiving a steady stream of characters
better than a slightly slower baud rate.

Changing the font
The font ROM consists of groups of
eight 8-bit hexadecimal values inside
the three FONT blocks. The top-most
block encodes ASCII codes 0-63, the
second 64-127, and the third 128-191.
The most significant bit is at left,
and the least significant bit at right,
with the data in rows in order from
top to bottom.
Refer to Fig.3, which shows how the
letter “A” is encoded (it is found at ad-
dresses 0x08 to 0x0F near the top of
the second font ROM block).
The whole font is shown in Screen4.

Changing the colours
The colours are formed by a similar
bitmap, with sixteen 6-bit hexadeci-
mal entries.
The two most significant bits are
for the blue level, the middle two bits
for the green, and the bottom two bits
for red.
Thus 0x00 is black and 0x3F is
white, as per the first two entries, with
the third entry 0x03 being red.
Because the foreground and back-
ground colours are stored in separate
ROMs, you could provide different
colour maps for each, but that might
be a bit confusing to use.

I/O pin assignments
Finally, you may wish to map the
serial data to a different pin, so you
aren’t using the USB/serial converter.
This is done by changing the pin con-
nected to the “rx” input of the UART
module, as shown in Screen5.
We recommend using the “TR” or
“BR” groups of pins for I/O; these are
the rows of solder pads along the edges
of the board.
Refer to the iCEstick manual to
check which pin is which.
Take care as the pins are only rated
for 3.3V I/O levels, so directly con-
necting a 5V microcontroller is not
recommended, and a level converter
or voltage divider should definitely be
used in that case.
Free download pdf