Skip to content

Commit df9c919

Browse files
committed
111.949MHz/1A7C: UART, Font,
* A few adjustments and bugs fixes have been made to make the UART more reliable. The clock has been changed slightly to more accurately reflect the UART timing and frame errors are detected correctly. One extra stop bit was being added/being required than should have been needed, this has been fixed in configuration. * The default font has been improved with a better character range, by default KOI8-R encoded 8x12 terminus is used. * The new graphics mode test code stuff has been removed, I cannot think of a good way of adding this mode in without making everything much more complicated, so I will leave it out for now. * The image has shrunk slightly, and less memory is used in the metacompiler. * The ANSI test suite now works correctly when transferred over the UART.
1 parent cf11dcd commit df9c919

File tree

11 files changed

+1901
-1891
lines changed

11 files changed

+1901
-1891
lines changed

embed.fth

+73-54
Large diffs are not rendered by default.

font.bin

+835-835
Large diffs are not rendered by default.

fonts/terminus.bin

+831-831
Large diffs are not rendered by default.

makefile

+2-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ EFORTH=h2.hex
9595
h2${EXE}: h2.c h2.h
9696
${CC} ${CFLAGS} -std=c99 $< -o $@
9797

98-
embed${EXE}: embed.o
98+
embed${EXE}: embed.c
99+
${CC} ${CFLAGS} -std=c99 $< -o $@
99100

100101
${EFORTH}: embed${EXE} embed.blk embed.fth
101102
${DF}embed${EXE} embed.blk $@ embed.fth

readme.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,10 @@ interface with devices on the [Nexys3][] board:
258258
* [VGA][] output device, text mode only, 80 by 40 characters from
259259
<http://www.javiervalcarce.eu/html/vhdl-vga80x40-en.html>. This has
260260
been heavily modified from the original, which now implements most of a
261-
[VT100][] terminal emulator.
261+
[VT100][] terminal emulator. This has two fonts available to it:
262+
- [Terminus][]/[KOI8-R][] (Default)
263+
- Latin [ISO-8859-15][] (Secondary Font) from
264+
<https://git.kernel.org/pub/scm/linux/kernel/git/legion/kbd.git>
262265
* [Timer][] in [timer.vhd][].
263266
* [UART][] (Rx/Tx) in [uart.vhd][].
264267
* [PS/2][] Keyboard
@@ -1213,6 +1216,9 @@ a text buffer to it would help in developing code for the platform.
12131216
[embed]: https://github.com/howerj/embed
12141217
[SDL]: https://www.libsdl.org/
12151218
[Apache 2.0]: https://www.apache.org/licenses/LICENSE-2.0.html
1219+
[KOI8-R]: https://en.wikipedia.org/wiki/KOI8-R
1220+
[Terminus]: http://terminus-font.sourceforge.net/
1221+
[ISO-8859-15]: https://en.wikipedia.org/wiki/ISO/IEC_8859-15
12161222

12171223
<!--
12181224

t/ansi.fth

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ WORDLIST CONSTANT COOL-TEXT ( <_< - way cool )
1111
COOL-TEXT >ORDER DEFINITIONS
1212
VARIABLE COOL-CHARACTER CHAR * COOL-CHARACTER !
1313
: BYE BYE ;
14-
: CR CR ;
14+
: CR $D EMIT $A EMIT ;
1515
: {{ CR COOL-TEXT >ORDER DUP ;
1616
: >_> CHAR COOL-CHARACTER ! ;
1717
: <_< [CHAR] * COOL-CHARACTER ! ;

tb.vhd

+9-11
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,16 @@ architecture testing of tb is
3939
);
4040

4141
constant number_of_interrupts: positive := 8;
42-
constant uart_baud: positive := 115200;
42+
constant uart_baud: positive := 115200;
4343
constant configuration_file_name: string := "tb.cfg";
4444
constant uart_tx_time: time := (10*1000 ms) / 115200;
4545
constant uart_default_input: std_ulogic_vector(7 downto 0) := x"AA";
4646
constant reset_period_us: natural := 1;
4747
constant jitter_on: boolean := false;
48-
4948
constant clock_period: time := 1000 ms / g.clock_frequency;
49+
constant tb_vga_on: boolean := false;
50+
constant tb_uart_on: boolean := false;
51+
constant tb_util_on: boolean := false;
5052

5153
-- Test bench configurable options --
5254

@@ -169,15 +171,11 @@ begin
169171
mem_addr => mem_addr,
170172
mem_data => mem_data);
171173

172-
uut_util: work.util.util_tb generic map(g => g);
173-
uut_vga: work.vga_pkg.vt100_tb generic map(g => g);
174-
175-
-- The "io_pins_tb" works correctly, however in GHDL 0.29, compiled under
176-
-- Windows, fails to simulate this component correctly, resulting
177-
-- in a crash. This does not affect the Linux build of GHDL. It has
178-
-- something to do with 'Z' values for std_logic types.
179-
180-
uut_io_pins: work.util.io_pins_tb generic map(g => g);
174+
-- NB. It would be nice to configure these as off/on, as well as
175+
-- controlling how long they run for from here.
176+
util_g: if tb_util_on generate uut_util: work.util.util_tb generic map(g => g); end generate;
177+
vga_g: if tb_vga_on generate uut_vga: work.vga_pkg.vt100_tb generic map(g => g); end generate;
178+
uart_g: if tb_uart_on generate uut_uart: work.uart_pkg.uart_tb generic map(g => g); end generate;
181179

182180
uart_0_blk: block
183181
signal uart_clock_rx_we, uart_clock_tx_we, uart_control_we: std_ulogic := '0';

top.vhd

+18-34
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ architecture behav of top is
7575
constant number_of_interrupts: positive := 8;
7676
constant number_of_led_displays: positive := 4;
7777
constant timer_period_us: positive := 20000;
78+
constant use_sine: boolean := false;
7879

7980
-- Signals
8081
signal rst: std_ulogic := '0';
@@ -151,12 +152,9 @@ architecture behav of top is
151152
signal mem_data_o: std_ulogic_vector(15 downto 0) := (others => '0');
152153
signal mem_control_we: std_ulogic := '0';
153154

154-
-- signal sine_we: std_ulogic := '0';
155-
-- signal sine: std_ulogic_vector(15 downto 0) := (others => '0');
155+
signal sine_we: std_ulogic := '0';
156+
signal sine: std_ulogic_vector(15 downto 0) := (others => '0');
156157

157-
signal vt100_raw_addr_we: std_ulogic := '0';
158-
signal vt100_raw_data_we: std_ulogic := '0';
159-
signal vt100_raw_do: std_ulogic_vector(15 downto 0) := (others => '0');
160158
begin
161159
-------------------------------------------------------------------------------
162160
-- The Main components
@@ -170,6 +168,8 @@ begin
170168
clk => clk,
171169
rst => rst);
172170

171+
-- TODO: Add interrupts on video blanking periods, which should
172+
-- make writing graphics code easier.
173173
cpu_irc(0) <= btnu_d; -- configurable CPU reset (can mask this)
174174
cpu_irc(1) <= not rx_fifo_empty;
175175
cpu_irc(2) <= rx_fifo_full;
@@ -253,10 +253,9 @@ begin
253253
uart_clock_rx_we <= '1' when is_write and selector = x"A" else '0';
254254
uart_control_we <= '1' when is_write and selector = x"B" else '0';
255255

256-
-- sine_we <= '1' when is_write and selector = x"C" else '0';
257-
258-
vt100_raw_addr_we <= '1' when is_write and selector = x"C" else '0';
259-
vt100_raw_data_we <= '1' when is_write and selector = x"D" else '0';
256+
sine_o: if use_sine generate
257+
sine_we <= '1' when is_write and selector = x"C" else '0';
258+
end generate;
260259
end block;
261260

262261
io_read: process(
@@ -274,8 +273,7 @@ begin
274273
timer_counter_o,
275274

276275
vga_data_busy,
277-
vt100_raw_do,
278-
-- sine,
276+
sine,
279277

280278
mem_data_o)
281279
begin
@@ -304,30 +302,21 @@ begin
304302
when "100" =>
305303
io_din <= mem_data_o;
306304
when "101" =>
307-
io_din <= vt100_raw_do;
308-
-- io_din <= sine;
305+
if use_sine then
306+
io_din <= sine;
307+
end if;
309308
when others => io_din <= (others => '0');
310309
end case;
311310
end process;
312311

313312
--- Sine ----------------------------------------------------------
314-
-- sine_block: block
315-
-- signal x, s: std_ulogic_vector(15 downto 0);
316-
-- begin
317-
-- reg_sin: work.util.reg
318-
-- generic map(g => g, N => x'length)
319-
-- port map(clk => clk, rst => rst, we => sine_we, di => io_dout, do => x);
320-
--
321-
-- sine_fifo_0: work.util.sine generic map(g => g) port map(x => x, s => s);
322-
--
323-
-- reg_sout: work.util.reg
324-
-- generic map(g => g, N => x'length)
325-
-- port map(clk => clk, rst => rst, we => '1', di => s, do => sine);
326-
--
327-
-- end block;
313+
sine_gen_0: if use_sine generate
314+
sine_0: work.util.sine
315+
generic map(g => g)
316+
port map(clk => clk, rst => rst, xwe => sine_we, x => io_dout, s => sine);
317+
end generate;
328318
--- Sine ----------------------------------------------------------
329319

330-
331320
--- UART ----------------------------------------------------------
332321
uart_fifo_0: work.uart_pkg.uart_top
333322
generic map (g => g, baud => uart_baud, use_fifo => false)
@@ -390,12 +379,7 @@ begin
390379
we => vga_data_we,
391380
char => vga_data,
392381
busy => vga_data_busy,
393-
o_vga => o_vga,
394-
395-
raw_addr_we => vt100_raw_addr_we,
396-
raw_data_we => vt100_raw_data_we,
397-
raw_di => io_dout,
398-
raw_do => vt100_raw_do);
382+
o_vga => o_vga);
399383
end generate;
400384

401385
-- Test code

uart.vhd

+52-24
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
--
1+
-- FILE: uart.vhd
22
-- BRIEF: UART TX/RX module
33
-- LICENSE: MIT
44
-- COPYRIGHT: Richard James Howe (2019)
@@ -323,38 +323,44 @@ architecture structural of uart_core is
323323
signal rx_fail: std_ulogic_vector(1 downto 0);
324324
signal rx_ok_buf: std_ulogic;
325325
signal do, do_c, do_n: std_ulogic_vector(rx_do'range);
326+
signal fail_c, fail_n: std_ulogic_vector(1 downto 0);
326327
signal nd_c, nd_n: std_ulogic; -- new data
327328
begin
328-
rx_ok_buf <= not (rx_fail(0) or rx_fail(1)) after g.delay;
329-
rx_ok <= rx_ok_buf after g.delay;
329+
rx_ok_buf <= not (fail_c(0) or fail_c(1)) after g.delay;
330+
rx_ok <= rx_ok_buf;
330331
rx_do <= do after g.delay;
331332
rx_nd <= nd_c and rx_ok_buf after g.delay; -- no new data if there are errors
332333

333334
process (clk, rst)
334335
begin
335336
if rst = '1' and g.asynchronous_reset then
336-
do_c <= (others => '0') after g.delay;
337-
nd_c <= '0' after g.delay;
337+
do_c <= (others => '0') after g.delay;
338+
fail_c <= (others => '0') after g.delay;
339+
nd_c <= '0' after g.delay;
338340
elsif rising_edge(clk) then
339341
if rst = '1' and not g.asynchronous_reset then
340-
do_c <= (others => '0') after g.delay;
341-
nd_c <= '0' after g.delay;
342+
do_c <= (others => '0') after g.delay;
343+
fail_c <= (others => '0') after g.delay;
344+
nd_c <= '0' after g.delay;
342345
else
343-
do_c <= do_n after g.delay;
344-
nd_c <= nd_n after g.delay;
346+
do_c <= do_n after g.delay;
347+
nd_c <= nd_n after g.delay;
348+
fail_c <= fail_n after g.delay;
345349
end if;
346350
end if;
347351
end process;
348352

349-
process (do_c, do, nd_c, rx_we, rx_re)
353+
process (do_c, do, nd_c, rx_we, rx_re, fail_c, rx_fail)
350354
begin
351-
do_n <= do_c after g.delay;
352-
nd_n <= nd_c after g.delay;
355+
do_n <= do_c after g.delay;
356+
nd_n <= nd_c after g.delay;
357+
fail_n <= fail_c after g.delay;
353358
if rx_we = '1' then
354-
do_n <= do after g.delay;
355-
nd_n <= '1' after g.delay;
359+
nd_n <= '1' after g.delay;
360+
do_n <= do after g.delay;
361+
fail_n <= rx_fail after g.delay;
356362
elsif rx_re = '1' then
357-
nd_n <= '0' after g.delay;
363+
nd_n <= '0' after g.delay;
358364
end if;
359365
end process;
360366

@@ -608,7 +614,7 @@ begin
608614
state_n <= idle after g.delay;
609615
when idle =>
610616
count_n <= 0 after g.delay;
611-
if rx_sync = '0' and majority = '1' then
617+
if rx_sync = '0' then -- and majority = '1' then
612618
state_n <= start after g.delay;
613619
cr <= '1' after g.delay;
614620
sr_n <= (others => '0') after g.delay;
@@ -653,7 +659,6 @@ begin
653659
state_n <= done after g.delay; -- frame error
654660
fail_n(0) <= '1' after g.delay;
655661
elsif count_c = ctr_stop_bits(ctr_c) then
656-
count_n <= 0 after g.delay;
657662
state_n <= done after g.delay;
658663
else
659664
count_n <= count_c + 1 after g.delay;
@@ -662,6 +667,9 @@ begin
662667
when done => -- The consuming module needs to store rx_c/fail_c immediately
663668
we <= '1' after g.delay;
664669
state_n <= idle after g.delay;
670+
--rx_n <= (others => '0') after g.delay;
671+
--sr_n <= (others => '0') after g.delay;
672+
--fail_n <= (others => '0') after g.delay;
665673
end case;
666674

667675
if ctr_we = '1' then
@@ -817,11 +825,17 @@ architecture testing of uart_tb is
817825
constant clock_period: time := 1000 ms / g.clock_frequency;
818826
signal rst, clk: std_ulogic := '1';
819827
signal stop: boolean := false;
828+
signal loopback: boolean := true;
820829
signal tx, rx: std_ulogic;
821830
signal tx_ok, rx_ok: std_ulogic;
822831
signal tx_we, rx_re: std_ulogic := '0';
823832
signal rx_nd: std_ulogic;
824833
signal di, do: std_ulogic_vector(7 downto 0);
834+
835+
signal reg: std_ulogic_vector(15 downto 0);
836+
signal clock_reg_tx_we: std_ulogic;
837+
signal clock_reg_rx_we: std_ulogic;
838+
signal control_reg_we: std_ulogic;
825839
begin
826840
-- duration: process begin wait for 20000 us; stop <= true; wait; end process;
827841
clk_process: process
@@ -843,7 +857,7 @@ begin
843857
stimulus: process
844858
procedure write(data: std_ulogic_vector(di'range)) is
845859
begin
846-
wait for clock_period;
860+
wait for clock_period * 1;
847861
while tx_ok = '0' loop
848862
wait for clock_period;
849863
end loop;
@@ -856,6 +870,19 @@ begin
856870
di <= x"00";
857871
wait until rst = '0';
858872
wait for clock_period;
873+
reg <= x"8080";
874+
control_reg_we <= '1';
875+
wait for clock_period;
876+
control_reg_we <= '0';
877+
reg <= x"0036";
878+
clock_reg_tx_we <= '1';
879+
wait for clock_period;
880+
clock_reg_tx_we <= '0';
881+
clock_reg_rx_we <= '1';
882+
reg <= x"0035";
883+
wait for clock_period;
884+
clock_reg_rx_we <= '0';
885+
wait for clock_period;
859886

860887
write(x"AA");
861888
write(x"BB");
@@ -866,7 +893,8 @@ begin
866893
while tx_ok = '0' loop
867894
wait for clock_period;
868895
end loop;
869-
896+
loopback <= false;
897+
wait for clock_period * 50000;
870898
stop <= true;
871899
wait;
872900
end process;
@@ -884,7 +912,7 @@ begin
884912
wait;
885913
end process;
886914

887-
rx <= tx; -- loop back test
915+
rx <= tx when loopback else '0'; -- loop back test
888916

889917
uut: work.uart_pkg.uart_core
890918
generic map(g => g)
@@ -900,10 +928,10 @@ begin
900928
rx_nd => rx_nd,
901929
rx_re => rx_re,
902930
rx_do => do,
903-
reg => (others => '0'),
904-
clock_reg_tx_we => '0',
905-
clock_reg_rx_we => '0',
906-
control_reg_we => '0'
931+
reg => reg,
932+
clock_reg_tx_we => clock_reg_tx_we,
933+
clock_reg_rx_we => clock_reg_rx_we,
934+
control_reg_we => control_reg_we
907935
);
908936
end architecture;
909937

0 commit comments

Comments
 (0)