Skip to content

Commit b6082ed

Browse files
committed
111.949MHz/1A82: Added sine/cosine test module
* A sine/cosine module, that needs testing in the hardware, has been added. It requires multiple multipliers however (a resource sharing version might be better). * xorshift PRNG has been added to the main program. * Minor renaming/code formatting changes
1 parent 226f606 commit b6082ed

File tree

2 files changed

+179
-36
lines changed

2 files changed

+179
-36
lines changed

embed.fth

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,8 @@ $400 tconstant b/buf ( size of a block )
332332
0 tlocation _forth-wordlist ( set at the end near the end of the file )
333333
0 tlocation _system ( system specific vocabulary )
334334
$0 tvariable >in ( Hold character pointer when parsing input )
335+
1 tlocation seed1 ( PRNG seed; never set to zero )
336+
1 tlocation seed2 ( PRNG seed; never set to zero )
335337
$0 tvariable state ( compiler state variable )
336338
$0 tvariable hld ( Pointer into hold area for numeric output )
337339
$A tvariable base ( Current output radix )
@@ -806,9 +808,22 @@ h: parse-string [char] " word count+ cp! ; ( ccc" -- )
806808
h: ?abort swap if print cr abort exit then drop ; ( u a -- )
807809
h: (abort) do$ ?abort ; ( -- )
808810
: abort" compile (abort) parse-string ; immediate compile-only ( u -- )
809-
xchange _forth-wordlist _system
811+
812+
\ See:
813+
\ <https://b2d-f9r.blogspot.com/2010/08/16-bit-xorshift-rng-now-with-more.html>
814+
\
815+
\ For a super tiny N-bit PRNG use; "x+=(x*x) | 5;", you can only use the
816+
\ highest bit however.
817+
\ See: <http://www.woodmann.com/forum/showthread.php?3100-super-tiny-PRNG>
818+
: random
819+
seed1 @ dup 5 lshift xor
820+
seed2 @ seed1 !
821+
dup 3 rshift xor
822+
seed2 @ dup 1 rshift xor xor dup seed2 ! ;
810823
h: 40ns begin dup while 1- repeat drop ; ( n -- : wait for 'n'*40ns + 30us )
811824
: ms for 25000 40ns next ; ( n -- : wait for 'n' milliseconds )
825+
826+
xchange _forth-wordlist _system
812827
: segments! $400E ! ; ( u -- : write to 4 7-segment hex displays )
813828
: led! $4006 ! ; ( u -- : write to 8 LEDs )
814829
: switches $4006 @ ; ( -- u : retrieve switch on/off for 8 switches )
@@ -824,8 +839,7 @@ h: (irq)
824839
: irq $0040 $4010 ! [-1] timer! 1 ien! ;
825840
h: uart? ( uart-register -- c -1 | 0 : generic UART input functions )
826841
dup @ $0100 and if drop 0x0000 exit then dup $0400 swap ! @ $FF and [-1] ;
827-
\ : rx? $4000 uart? if [-1] exit then $4002 uart? ; ( -- c -1|0: rx uart/ps2 )
828-
: rx? $4000 uart? ; ( -- c -1|0: rx uart/ps2 )
842+
: rx? $4000 uart? if [-1] exit then $4002 uart? ; ( -- c -1|0: rx uart/ps2 )
829843
h: uart! ( c uart-register -- )
830844
begin dup @ $1000 and 0= until swap $2000 or swap ! ;
831845
\ : tx! dup $4002 uart! ( VGA/VT-100 ) $4000 uart! ( UART ) ;
@@ -969,17 +983,17 @@ h: (order) ( w wid*n n -- wid*n w n )
969983
: +order dup>r -order get-order r> swap 1+ set-order ; ( wid -- )
970984
: editor editor-voc +order ; ( -- : load editor vocabulary )
971985

972-
h: updated? block-dirty @ ; ( -- f )
986+
\ h: updated? block-dirty @ ; ( -- f )
973987
: update [-1] block-dirty ! ; ( -- )
974988
h: blk-@ blk @ ;
975-
: +block blk-@ + ; ( n -- k )
976-
h: clean-buffers 0 block-dirty ! ;
977-
h: empty-buffers clean-buffers 0 blk ! ; ( -- )
978-
h: save-buffers ( -- )
979-
blk-@ 0= updated? 0= or if exit then
989+
h: +block blk-@ + ; ( n -- k )
990+
\ h: clean-buffers 0 block-dirty ! ;
991+
\ h: empty-buffers clean-buffers 0 blk ! ; ( -- )
992+
: flush
993+
blk-@ 0= block-dirty @ d0= if exit then
980994
block-buffer b/buf blk-@ <save> @execute throw
981-
clean-buffers ;
982-
: flush save-buffers empty-buffers ;
995+
0 block-buffer ! ( <- clean-buffer )
996+
0 blk ! ; ( <- empty-buffers )
983997
h: ?block if $23 -throw exit then ;
984998
: block ( k -- a )
985999
1depth
@@ -1116,26 +1130,26 @@ h: mblock ( a u k -- f )
11161130

11171131
\ TODO Add to a VT100/ANSI Escape Sequence wordset
11181132

1119-
h: CSI $1B emit [char] [ emit ;
1133+
h: CSI $1B emit [char] [ emit ; ( -- )
11201134
h: 10u. base@ >r decimal 0 <# #s #> type r> base! ; ( u -- )
1121-
: ansi swap CSI 10u. emit ; ( n c -- )
1135+
: ansi swap CSI 10u. emit ; ( n c -- )
11221136
xchange _system _forth-wordlist
11231137
: at-xy CSI 10u. $3B emit 10u. [char] H emit ; ( x y -- ) \ <at-xy> @execute
1124-
: page 2 [char] J ansi 1 1 at-xy ; ( -- ) \ <page> @execute
1138+
: page 2 [char] J ansi 1 1 at-xy ; ( -- ) \ <page> @execute
11251139
xchange _forth-wordlist _system
1126-
: sgr [char] m ansi ; ( -- )
1127-
: up [char] A ansi ;
1128-
: down [char] B ansi ;
1129-
: right [char] C ansi ;
1130-
: left [char] D ansi ;
1140+
: sgr [char] m ansi ; ( -- : emit an SGR )
1141+
: up [char] A ansi ; ( u -- : move the cursor up )
1142+
: down [char] B ansi ; ( u -- : move the cursor down )
1143+
: right [char] C ansi ; ( u -- : move the cursor right )
1144+
: left [char] D ansi ; ( u -- : move the cursor left )
11311145

1132-
h: tableu
1146+
h: tableu ( -- )
11331147
$7 for
11341148
$A right $7 r@ - $28 + dup sgr u. colon-space
11351149
$7 for $7 r@ - $1E + dup sgr u. next cr
11361150
next ;
11371151

1138-
: table page 0 sgr $2 down tableu 1 sgr $2 down tableu 0 sgr ;
1152+
: table page 0 sgr $2 down tableu 1 sgr $2 down tableu 0 sgr ; ( -- )
11391153
\ : nuf? key? if drop [-1] exit then 0x0000 ; ( -- f )
11401154
xchange _system _forth-wordlist
11411155

util.vhd

Lines changed: 144 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@
1717
--| Cosine Transform, Pulse Width/Code/Position Modulation modules, so long as
1818
--| they are fairly generic and synthesizable.
1919
--|
20-
--| An alternative to CORDIC, is this sin-cosine implementation written in
21-
--| Verilog <https://github.com/jamesbowman/sincos>. It requires a multiplier
22-
--| however.
20+
--| Potential improvements to the library:
21+
--| - Optional registers on either input or output, selectable by a generic
22+
--| - Better timing models
23+
--| - More assertions
24+
--| - Put a modules state in a record that represents that state, to make
25+
--| assignment and handling of that state easier.
2326
--|
2427
--| @author Richard James Howe
2528
--| @copyright Copyright 2017, 2019 Richard James Howe
@@ -524,6 +527,24 @@ package util is
524527
generic (g: common_generics);
525528
end component;
526529

530+
component sine is
531+
generic (g: common_generics);
532+
port (
533+
x: in std_ulogic_vector(15 downto 0);
534+
s: out std_ulogic_vector(15 downto 0));
535+
end component;
536+
537+
component cosine is
538+
generic (g: common_generics);
539+
port (
540+
x: in std_ulogic_vector(15 downto 0);
541+
s: out std_ulogic_vector(15 downto 0));
542+
end component;
543+
544+
component sine_tb is
545+
generic (g: common_generics);
546+
end component;
547+
527548
function max(a: natural; b: natural) return natural;
528549
function min(a: natural; b: natural) return natural;
529550
function reverse (a: in std_ulogic_vector) return std_ulogic_vector;
@@ -892,6 +913,7 @@ begin
892913
uut_gray: work.util.gray_tb generic map (g => g);
893914
uut_ham: work.util.hamming_7_4_tb generic map (g => g); -- Oink!
894915
uut_vga: work.util.vga_tb generic map (g => g, simulation_us => 1 us);
916+
uut_sine: work.util.sine_tb generic map (g => g);
895917
uut_7_seg: work.util.led_7_segment_display_tb generic map (g => g);
896918

897919
stimulus_process: process
@@ -2292,7 +2314,7 @@ end architecture;
22922314
-- state to fetch the operand and another register, or more states.
22932315
--
22942316
-- @todo Test in hardware, document, make assembler, and a project that
2295-
-- just contains an instantiation of this core, Select CPU behaviour with
2317+
-- just contains an instantiation of this core, Select CPU behavior with
22962318
-- generics (instructions, branch conditions...)
22972319
--
22982320

@@ -2805,7 +2827,7 @@ entity reset_generator is
28052827
rst: out std_logic := '0'); -- reset out!
28062828
end entity;
28072829

2808-
architecture behaviour of reset_generator is
2830+
architecture behavior of reset_generator is
28092831
constant cycles: natural := (g.clock_frequency / 1000000) * reset_period_us;
28102832
subtype counter is unsigned(max(1, n_bits(cycles) - 1) downto 0);
28112833
signal c_c, c_n: counter := (others => '0');
@@ -2876,7 +2898,7 @@ entity bit_count is
28762898
count: out std_ulogic_vector(n_bits(N) downto 0));
28772899
end entity;
28782900

2879-
architecture behaviour of bit_count is
2901+
architecture behavior of bit_count is
28802902
begin
28812903
process (bits)
28822904
constant zero: unsigned(count'high - 1 downto count'low) := (others => '0');
@@ -2946,7 +2968,7 @@ entity majority is
29462968
tie: out std_ulogic);
29472969
end entity;
29482970

2949-
architecture behaviour of majority is
2971+
architecture behavior of majority is
29502972
signal count: std_ulogic_vector(n_bits(N) downto 0) := (others => '0');
29512973
-- It might be worth handling up to five or so bits in combinatorial
29522974
-- logic, or it might not.
@@ -3122,7 +3144,7 @@ entity delay_line is
31223144
do: out std_ulogic_vector(width - 1 downto 0));
31233145
end entity;
31243146

3125-
architecture behaviour of delay_line is
3147+
architecture behavior of delay_line is
31263148
type delay_line_t is array(integer range 0 to depth) of std_ulogic_vector(di'range);
31273149
signal sigs: delay_line_t := (others => (others => '0'));
31283150
begin
@@ -3200,7 +3222,7 @@ entity gray_encoder is
32003222
do: out std_ulogic_vector(N - 1 downto 0));
32013223
end entity;
32023224

3203-
architecture behaviour of gray_encoder is
3225+
architecture behavior of gray_encoder is
32043226
begin
32053227
gry: for i in N - 1 downto 0 generate
32063228
first: if i = (N - 1) generate
@@ -3223,7 +3245,7 @@ entity gray_decoder is
32233245
do: out std_ulogic_vector(N - 1 downto 0));
32243246
end entity;
32253247

3226-
architecture behaviour of gray_decoder is
3248+
architecture behavior of gray_decoder is
32273249
begin
32283250
gry: for i in N - 1 downto 0 generate
32293251
first: if i = (N - 1) generate
@@ -3296,7 +3318,7 @@ entity parity_module is
32963318
port (di: in std_ulogic_vector(N - 1 downto 0); do: out std_ulogic);
32973319
end entity;
32983320

3299-
architecture behaviour of parity_module is
3321+
architecture behavior of parity_module is
33003322
begin
33013323
do <= parity(di, even) after g.delay;
33023324
end architecture;
@@ -3327,7 +3349,7 @@ entity hamming_7_4_encoder is
33273349
parity: out std_ulogic);
33283350
end entity;
33293351

3330-
architecture behaviour of hamming_7_4_encoder is
3352+
architecture behavior of hamming_7_4_encoder is
33313353
signal p1, p2, p3: std_ulogic := '0';
33323354
begin
33333355
p1 <= di(0) xor di(1) xor di(3) after g.delay;
@@ -3357,7 +3379,7 @@ entity hamming_7_4_decoder is
33573379
single, double: out std_ulogic);
33583380
end entity;
33593381

3360-
architecture behaviour of hamming_7_4_decoder is
3382+
architecture behavior of hamming_7_4_decoder is
33613383
signal s: std_ulogic_vector(2 downto 0) := (others => '0');
33623384
signal co, ct, dip: std_ulogic_vector(di'high + 1 downto 0) := (others => '0');
33633385
signal cp: std_ulogic := '0';
@@ -3685,7 +3707,7 @@ end architecture;
36853707
--| Each of the display shares a common anode for all of its LEDs, this can be
36863708
--| used to select an individual display
36873709

3688-
library ieee,work;
3710+
library ieee, work;
36893711
use ieee.std_logic_1164.all;
36903712
use ieee.numeric_std.all;
36913713
use work.util.all;
@@ -3891,7 +3913,7 @@ begin
38913913
end process;
38923914
end architecture;
38933915

3894-
library ieee,work;
3916+
library ieee, work;
38953917
use ieee.std_logic_1164.all;
38963918
use ieee.numeric_std.all;
38973919
use work.util.all;
@@ -3935,4 +3957,111 @@ begin
39353957
end architecture;
39363958

39373959
------------------------- LED Controller ------------------------------------------------------
3960+
------------------------- Sine / Cosine ------------------------------------------------------
3961+
-- Sine / Cosine calculation using multiplication
3962+
-- Half-inched from <https://github.com/jamesbowman/sincos>
3963+
-- Angles are input as signed Furmans (1 Furman = (1/pow(2, 16) of a circle))
3964+
-- 1 Degree is ~182 Furmans. 1 rad is ~10430 Furmans.
3965+
-- Result is signed scaled 16-bit integer; -1 = -32767, +1 = 32767
3966+
library ieee, work;
3967+
use ieee.std_logic_1164.all;
3968+
use ieee.numeric_std.all;
3969+
use work.util.all;
39383970

3971+
entity sine is
3972+
generic (g: common_generics);
3973+
port (
3974+
x: in std_ulogic_vector(15 downto 0);
3975+
s: out std_ulogic_vector(15 downto 0));
3976+
end entity;
3977+
3978+
architecture behavior of sine is
3979+
subtype val is signed(x'range);
3980+
subtype mul is signed((val'high * 2) + 1 downto 0);
3981+
function half_multiply_add(a, b, c: val) return val is
3982+
variable t: mul;
3983+
variable r: val;
3984+
begin
3985+
t := a * b;
3986+
r := t(t'high downto r'high + 1) + c;
3987+
return r;
3988+
end function;
3989+
signal n: signed(2 downto 0);
3990+
signal z, y, sums, sumc, sum1, cc, t0, t1, sa, so: val;
3991+
signal cc32: mul;
3992+
begin
3993+
y(1 downto 0) <= (others => '0') after g.delay;
3994+
y(15 downto 2) <= signed(x(13 downto 0)) after g.delay;
3995+
n <= signed(x(15 downto 13)) + "01" after g.delay;
3996+
z <= half_multiply_add(y, y, x"0000") after g.delay;
3997+
sumc <= half_multiply_add(z, x"0FBD", -x"4EE9") after g.delay;
3998+
sums <= half_multiply_add(z, x"04F8", -x"2953") after g.delay;
3999+
sum1 <= half_multiply_add(z, sums, x"6487") after g.delay;
4000+
cc32 <= t0 * t1 after g.delay;
4001+
cc <= cc32(cc32'high - 1 downto cc'high) after g.delay;
4002+
t0 <= z when n(1) = '1' else y after g.delay;
4003+
t1 <= sumc when n(1) = '1' else sum1 after g.delay;
4004+
sa <= cc + x"7FFF" when n(1) = '1' else cc after g.delay;
4005+
so <= -sa when n(2) = '1' else sa after g.delay;
4006+
s <= std_ulogic_vector(so) after g.delay;
4007+
end architecture;
4008+
4009+
library ieee, work;
4010+
use ieee.std_logic_1164.all;
4011+
use ieee.numeric_std.all;
4012+
use work.util.all;
4013+
4014+
entity cosine is
4015+
generic (g: common_generics);
4016+
port (
4017+
x: in std_ulogic_vector(15 downto 0);
4018+
c: out std_ulogic_vector(15 downto 0));
4019+
end entity;
4020+
4021+
architecture behavior of cosine is
4022+
signal xn: std_ulogic_vector(c'range);
4023+
begin
4024+
xn <= std_ulogic_vector(signed(x) + x"4000");
4025+
calc: entity work.sine
4026+
generic map(g => g) port map(x => xn, s => c);
4027+
end architecture;
4028+
4029+
library ieee, work;
4030+
use ieee.std_logic_1164.all;
4031+
use ieee.numeric_std.all;
4032+
use work.util.all;
4033+
4034+
entity sine_tb is
4035+
generic (g: common_generics);
4036+
end entity;
4037+
4038+
architecture testing of sine_tb is
4039+
constant clock_period: time := 1000 ms / g.clock_frequency;
4040+
signal clk, rst: std_ulogic := '0';
4041+
signal stop: std_ulogic := '0';
4042+
4043+
constant number_of_led_displays: positive := 4;
4044+
signal x: std_ulogic_vector(15 downto 0);
4045+
signal s, c: std_ulogic_vector(x'range);
4046+
begin
4047+
cs: entity work.clock_source_tb
4048+
generic map (g => g, hold_rst => 2)
4049+
port map (stop => stop, clk => clk, rst => rst);
4050+
4051+
uut_c: entity work.sine generic map (g => g) port map (x => x, s => s);
4052+
uut_s: entity work.cosine generic map (g => g) port map (x => x, c => c);
4053+
4054+
stimulus_process: process
4055+
variable cnt: integer := -32768;
4056+
begin
4057+
x <= std_ulogic_vector(to_signed(cnt, x'length));
4058+
wait for clock_period * 2;
4059+
while cnt < 32768 loop
4060+
x <= std_ulogic_vector(to_signed(cnt, x'length));
4061+
wait for clock_period;
4062+
cnt := cnt + 182;
4063+
end loop;
4064+
stop <= '1';
4065+
wait;
4066+
end process;
4067+
end architecture;

0 commit comments

Comments
 (0)