non-working top level

This commit is contained in:
Niels Moseley 2017-10-23 02:15:45 +02:00
parent 2f89161c65
commit 704cd3d4cb
13 changed files with 8744 additions and 8 deletions

View File

@ -0,0 +1,357 @@
//
// Speecht256 top level
//
// Niels Moseley - Moseley Instruments 2017
// http://www.moseleyinstruments.com
//
//
module CONTROLLER (
clk, // global Speech256 clock
rst_an,
ldq, // load request, is high when new allophone can be loaded
data_in, // allophone input
data_stb, // allophone strobe input
period_out, // pitch period output
amp_out, // amplitude output
coeff_out, // 8-bit coefficient data out
coeff_stb, // '1' when coeff_out holds new coefficient data
period_done_in // should be '1' when the source finished a period
);
//////////// CLOCK //////////
input clk;
//////////// RESET, ACTIVE LOW //////////
input rst_an;
//////////// OUTPUTS //////////
output reg ldq;
output reg coeff_stb;
output reg signed [7:0] coeff_out;
output reg [15:0] amp_out;
output reg [7:0] period_out;
//output reg [7:0] dur_out;
//////////// INPUTS //////////
input [5:0] data_in;
input data_stb;
input source_stb_in;
input period_done_in; // used for duration counting
// internal counter and data registers
wire [7:0] rom_data;
reg [11:0] rom_addr;
reg [11:0] last_rom_addr;
reg [2:0] rom_addr_sel;
reg rom_en;
reg [3:0] jmpmsb;
reg jmpmsb_load;
reg [5:0] cur_allo;
reg [3:0] cur_cmd;
reg [3:0] cur_state;
reg [3:0] next_state;
reg [5:0] data_in_buf;
reg amp1_load, amp2_load;
reg period_load;
reg dur_load;
reg allo_load;
reg load_cur_cmd;
reg serve_pitch_data;
reg set_ldq, reset_ldq;
reg dur_cnt_clear;
wire serve_next_allo_data;
reg [15:0] amp_tmp;
reg [7:0] period_tmp;
reg [7:0] dur_tmp;
reg [7:0] duration;
reg [7:0] dur_cnt;
reg [2:0] coeff_cnt;
reg [1:0] coeff_cnt_update;
wire done;
CTRLROM u_ctrlrom (
.clk (clk),
.data (rom_data),
.addr (rom_addr),
.en (rom_en)
);
parameter ROM_ADDR_ZERO = 3'b000, // zero the ROM address
ROM_ADDR_INC = 3'b001, // increment the ROM address
ROM_ADDR_JMP = 3'b010, // jump to code
ROM_ADDR_ALLO = 3'b011, // read allophone jump address
ROM_ADDR_NOP = 3'b100;
parameter COEFF_CNT_ZERO = 2'b00, // zero coefficient counter
COEFF_CNT_NOP = 2'b01, // do nothing
COEFF_CNT_INC = 2'b10; // increment coefficient counter
always @(posedge clk, negedge rst_an)
begin
if (rst_an == 0)
begin
// reset values
amp_out <= 0;
period_out <= 8'd1;
rom_en <= 1;
rom_addr <= 0;
last_rom_addr <= 0;
cur_state <= 0;
cur_allo <= 0;
cur_cmd <= 0;
coeff_stb <= 0;
coeff_out <= 0;
coeff_cnt <= 0;
jmpmsb <= 0;
ldq <= 0;
dur_cnt <= 0;
duration <= 0;
end
else
begin
// clocked process
cur_state <= next_state;
case (coeff_cnt_update)
COEFF_CNT_ZERO:
coeff_cnt <= 0;
COEFF_CNT_NOP:
coeff_cnt <= coeff_cnt;
COEFF_CNT_INC:
coeff_cnt <= coeff_cnt + 1;
default:
coeff_cnt <= 0;
endcase
if (jmpmsb_load)
jmpmsb <= rom_data[3:0];
if (amp1_load)
amp_tmp[7:0] <= rom_data;
if (amp2_load)
amp_tmp[15:8] <= rom_data;
if (period_load)
period_tmp <= rom_data;
if (dur_load)
dur_tmp <= rom_data;
if (allo_load)
cur_allo <= data_in;
if (load_cur_cmd)
cur_cmd <= rom_data[3:0];
if (serve_pitch_data)
begin
duration <= dur_tmp;
amp_out <= amp_tmp;
period_out <= period_tmp;
end
if (set_ldq == 1)
ldq <= 1;
else if (reset_ldq == 1)
ldq <= 0;
if ((period_done_in == 1) && (!serve_next_allo_data))
begin
dur_cnt <= dur_cnt + 1;
end
if (dur_cnt_clear)
begin
dur_cnt <= 0;
end
last_rom_addr <= rom_addr;
end
end
assign serve_next_allo_data = (dur_cnt == duration) ? 1 : 0;
parameter S_IDLE = 4'd0,
S_JMPADDR1 = 4'd1,
S_JMPADDR2 = 4'd2,
S_JMPADDR3 = 4'd3,
S_CMDLOAD = 4'd4,
S_CMDDECODE= 4'd5,
S_LOADAMP1 = 4'd6,
S_LOADAMP2 = 4'd7,
S_LOADDUR = 4'd8,
S_LOADPERIOD= 4'd9,
S_SERVEGATE = 4'd10,
S_LOADCOEF1 = 4'd11,
S_LOADCOEF2 = 4'd12;
always @(*)
begin
// rom address multiplexer
case (rom_addr_sel)
ROM_ADDR_ZERO:
rom_addr <= 0;
ROM_ADDR_INC:
rom_addr <= last_rom_addr + 1;
ROM_ADDR_JMP:
rom_addr <= {jmpmsb, rom_data[7:0]};
ROM_ADDR_ALLO:
rom_addr <= {5'b00000, cur_allo, 1'b0};
ROM_ADDR_NOP:
rom_addr <= last_rom_addr;
default:
rom_addr <= 0;
endcase
end
always @(*)
begin
// ---------------------------------------------
// -------- MAIN FINITE STATE MACHINE ----------
// ---------------------------------------------
// FSM defaults:
rom_addr_sel <= ROM_ADDR_INC;
coeff_cnt_update <= COEFF_CNT_NOP;
next_state <= cur_state;
coeff_stb <= 0;
jmpmsb_load <= 0;
amp1_load <= 0;
amp2_load <= 0;
period_load <= 0;
dur_load <= 0;
allo_load <= 0;
load_cur_cmd <= 0;
set_ldq <= 0;
reset_ldq <= 0;
serve_pitch_data <= 0;
dur_cnt_clear <= 0;
case (cur_state)
S_IDLE:
begin
set_ldq <= 1;
if (serve_next_allo_data == 1)
begin
// we've run out of allophone data ..
end
if (data_stb == 1)
begin
allo_load <= 1;
next_state <= S_JMPADDR1;
end
rom_addr_sel <= ROM_ADDR_ZERO;
end
S_JMPADDR1:
begin
// get MSB of allophone address code
rom_addr_sel <= ROM_ADDR_ALLO;
next_state <= S_JMPADDR2;
end
S_JMPADDR2:
begin
// get LSB of allophone address code
jmpmsb_load <= 1;
rom_addr_sel <= ROM_ADDR_INC;
next_state <= S_CMDLOAD;
end
S_JMPADDR3:
begin
next_state <= S_CMDLOAD;
end
S_CMDLOAD:
begin
// perform jmp
rom_addr_sel <= ROM_ADDR_JMP;
next_state <= S_CMDDECODE;
reset_ldq <= 1;
end
S_CMDDECODE:
begin
// current command and
// terminate sequencer if
// CMD == 0xF
if (rom_data == 4'hF)
next_state <= S_IDLE; // end of command
else
begin
rom_addr_sel <= ROM_ADDR_INC;
next_state <= S_LOADAMP1;
end
load_cur_cmd <= 1;
//cur_cmd <= rom_data;
end
S_LOADAMP1: // load 16-bit AMP
begin
amp1_load <= 1;
rom_addr_sel <= ROM_ADDR_INC;
next_state <= S_LOADAMP2;
end
S_LOADAMP2:
begin
amp2_load <= 1;
rom_addr_sel <= ROM_ADDR_INC;
next_state <= S_LOADDUR;
end
S_LOADDUR:
begin
dur_load <= 1;
rom_addr_sel <= ROM_ADDR_INC;
next_state <= S_LOADPERIOD;
end
S_LOADPERIOD:
begin
period_load <= 1;
coeff_cnt_update <= COEFF_CNT_ZERO;
rom_addr_sel <= ROM_ADDR_INC;
next_state <= S_SERVEGATE;
end
S_SERVEGATE:
begin
rom_addr_sel <= ROM_ADDR_NOP;
if (serve_next_allo_data == 1)
begin
serve_pitch_data <= 1;
dur_cnt_clear <= 1;
next_state <= (cur_cmd == 4'd2) ? S_LOADCOEF1 : S_CMDDECODE;
end
end
S_LOADCOEF1:
// send F coefficient
begin
coeff_stb <= 1;
coeff_out <= rom_data;
coeff_cnt_update <= COEFF_CNT_INC;
rom_addr_sel <= ROM_ADDR_INC;
next_state <= S_LOADCOEF2;
end
S_LOADCOEF2:
// send B coefficient
begin
coeff_stb <= 1;
coeff_out <= rom_data;
if (coeff_cnt == 3'd6)
next_state <= S_CMDDECODE; // load next section
else
next_state <= S_LOADCOEF1; // next command
rom_addr_sel <= ROM_ADDR_INC;
end
default:
next_state <= S_IDLE;
endcase
end
endmodule

View File

@ -0,0 +1,64 @@
//
// PWMDAC testbench
//
// Niels Moseley - Moseley Instruments 2017
// http://www.moseleyinstruments.com
//
module CONTROLLER_TB;
reg clk, rst_an;
reg [5:0] data_in;
reg data_stb, serve_next;
reg period_done;
wire ldq;
wire signed [7:0] coeff;
wire coeff_load;
wire [7:0] period;
wire [15:0] amp;
wire [7:0] dur;
CONTROLLER u_controller (
.clk (clk),
.rst_an (rst_an),
.ldq (ldq),
.data_in (data_in),
.data_stb (data_stb),
.period_out (period),
.amp_out (amp),
.coeff_out (coeff),
.coeff_stb (coeff_load),
.period_done_in (period_done)
);
initial
begin
$dumpfile ("controller.vcd");
$dumpvars;
clk = 0;
rst_an = 0;
data_in = 6;
data_stb = 0;
period_done = 0;
#5
rst_an = 1;
#5
// load allophone
data_stb = 1;
#10
data_stb = 0;
serve_next = 1;
#300000
$finish;
end
always @(posedge clk)
begin
;
end
always
#5 clk = !clk;
endmodule

File diff suppressed because it is too large Load Diff

4018
verilog/controller/ctrlrom.v Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,117 @@
#
# Generate control rom for Speech256 project
#
# Copyright N.A. Moseley 2017 / Moseley Instruments
#
# The control rom is in a slightly different format
# than we need for the Verilog code, so in addition
# to making a ROM directry, we massage it a bit...
#
VerilogHeader = """
// This file was auto-generated,
// do not modify by hand!
module CTRLROM (
clk,
en,
addr,
data
);
input clk;
input en;
input [11:0] addr;
output reg [7:0] data;
always @(posedge clk)
begin
if (en)
case(addr)
"""
VerilogFooter = """ default: data <= 8'bXXXXXXXX;
endcase
end
endmodule
"""
RomAddress = 0;
def emitRomByte(b):
global RomAddress
global fout
fout.write(" 12'd"+str(RomAddress)+": data <= 8'd" + str(b) + ";\n")
RomAddress = RomAddress + 1;
def convertFilterCoeff(c):
# turn c into negative 8-bit number
# 1 -> 255
# 2 -> 254
# 255 -> 1
# 254 -> 2
# 128 -> xxx
# 0 -> 0
if (c == 0):
return 0
return (256-c);
fout = open('ctrlrom.v','wt')
with open('ctrlrom.hex', 'r') as fp:
hex_list = fp.readlines()
cmd_list = [int(c,16) for c in hex_list];
# generate header
fout.write(VerilogHeader)
# generate jump table
for I in range(0,0x7E):
emitRomByte(cmd_list[I])
counter = 0x7E
while (counter < len(cmd_list)):
cmd = cmd_list[counter];
if (cmd == 0): # JUMP INSTRUCTION
print("?")
elif (cmd == 1): # SET AMP AND PITCH
emitRomByte(cmd)
emitRomByte(cmd_list[counter+1]) # AMP LSB
emitRomByte(cmd_list[counter+2]) # AMP MSB
emitRomByte(cmd_list[counter+3]) # DUR
emitRomByte(cmd_list[counter+4]) # PITCH
counter = counter + 4
#print("SET AMP+PITCH")
elif (cmd == 2): # SET COEFFICIENTS
emitRomByte(cmd)
emitRomByte(cmd_list[counter+1]) # AMP LSB
emitRomByte(cmd_list[counter+2]) # AMP MSB
emitRomByte(cmd_list[counter+3]) # DUR
emitRomByte(cmd_list[counter+4]) # PITCH
emitRomByte(convertFilterCoeff(cmd_list[counter+10])) # F6
emitRomByte(convertFilterCoeff(cmd_list[counter+10+6])) # B6
emitRomByte(convertFilterCoeff(cmd_list[counter+9])) # F5
emitRomByte(convertFilterCoeff(cmd_list[counter+9+6])) # B5
emitRomByte(convertFilterCoeff(cmd_list[counter+8])) # F4
emitRomByte(convertFilterCoeff(cmd_list[counter+8+6])) # B4
emitRomByte(convertFilterCoeff(cmd_list[counter+7])) # F3
emitRomByte(convertFilterCoeff(cmd_list[counter+7+6])) # B3
emitRomByte(convertFilterCoeff(cmd_list[counter+6])) # F2
emitRomByte(convertFilterCoeff(cmd_list[counter+6+6])) # B2
emitRomByte(convertFilterCoeff(cmd_list[counter+5])) # F1
emitRomByte(convertFilterCoeff(cmd_list[counter+5+6])) # B1
counter = counter + 4 + 12
#print("SET COEFFS")
elif (cmd == 15): # SET COEFFICIENTS: # END OF COMMAND / 15
emitRomByte(cmd)
else:
print("*** ERROR ***")
break
counter = counter + 1
# generate footer
fout.write(VerilogFooter)
fout.close()

View File

@ -0,0 +1,7 @@
python genctrlrom.py
mkdir bin
del bin\controller.vvp
C:\iverilog\bin\iverilog -o bin\controller.vvp -m va_math -g2005 -s CONTROLLER_TB controller.v controller_tb.v ctrlrom.v
cd bin
C:\iverilog\bin\vvp controller.vvp -lxt2
cd ..

View File

@ -148,7 +148,7 @@ module FILTER (
if (do_accu)
begin
if (double_mode)
accu <= accu_in +{mul_result[14:0], 1'b0};
accu <= accu_in + {mul_result[14:0], 1'b0};
else
accu <= accu_in + mul_result;
end

View File

@ -12,9 +12,9 @@
module PWMDAC (
clk,
rst_an,
din,
din_ack,
dacout
din, // 16 bit signed data input
din_ack, // is high for 1 clock cycle after reading the din signal
dacout // 1-bit PWM output signal
);
//////////// CLOCK //////////

View File

@ -12,6 +12,7 @@ module SOURCE (
period, // period in 10kHz samples
amplitude, // unsigned 15-bit desired amplitude of source output
strobe, // when strobe == '1' a new source_out will be generated
period_done, // is set to '1' at the end of the period
source_out // signed 16-bit source output
);
@ -23,6 +24,7 @@ module SOURCE (
//////////// OUTPUTS //////////
output reg signed [15:0] source_out;
output reg period_done;
//////////// INPUTS //////////
input [14:0] amplitude;
@ -32,6 +34,7 @@ module SOURCE (
// internal counter and data registers
reg signed [7:0] periodcnt;
reg [16:0] lfsr;
reg last_strobe;
always @(posedge clk, negedge rst_an)
begin
@ -39,12 +42,17 @@ module SOURCE (
begin
// reset values
periodcnt <= 0;
period_done <= 1;
source_out <= 0;
last_strobe <= 0;
lfsr <= 17'h1; //note: never reset the LFSR to zero!
end
else
begin
if (strobe == 1)
// default value
period_done <= 0;
if ((strobe == 1) && (last_strobe == 0))
begin
// if period == 0, we need to generate noise
// else we generate a pulse wave
@ -53,8 +61,11 @@ module SOURCE (
// ------------------------------------------------------------
// LFSR NOISE GENERATOR
// ------------------------------------------------------------
if (periodcnt == 64)
periodcnt <= 0;
if (periodcnt == 64)
begin
periodcnt <= 0;
period_done <= 1;
end
else
periodcnt <= periodcnt + 1;
@ -69,7 +80,10 @@ module SOURCE (
// ------------------------------------------------------------
// make periodcnt count from 0 .. period-1
if (periodcnt == period)
periodcnt <= 0;
begin
periodcnt <= 0;
period_done <= 1;
end
else
periodcnt <= periodcnt + 1;
@ -79,6 +93,7 @@ module SOURCE (
source_out <= 16'h0000;
end
end
last_strobe <= strobe;
end
end

View File

@ -13,6 +13,7 @@ module SOURCE_TB;
reg [7:0] cnt;
wire signed [15:0] source_out;
wire period_done;
SOURCE u_source (
.clk (clk),
@ -20,6 +21,7 @@ module SOURCE_TB;
.period (period),
.amplitude (amp),
.strobe (strobe),
.period_done (period_done)
.source_out (source_out)
);

View File

@ -0,0 +1,6 @@
mkdir bin
del bin\speech256_top.vvp
C:\iverilog\bin\iverilog -o bin\speech256_top.vvp -m va_math -g2005 -s SPEECH256_TOP_TB speech256_top.v speech256_top_tb.v ..\filter\filter.v ..\source\source.v ..\spmul\spmul.v ..\pwmdac\pwmdac.v ..\controller\controller.v ..\controller\ctrlrom.v
cd bin
C:\iverilog\bin\vvp speech256_top.vvp -lxt2
cd ..

View File

@ -0,0 +1,102 @@
//
// Speecht256 top level
//
// Niels Moseley - Moseley Instruments 2017
// http://www.moseleyinstruments.com
//
//
module SPEECH256_TOP (
clk, // global Speech256 clock
rst_an,
ldq, // load request, is high when new allophone can be loaded
data_in, // allophone input
data_stb, // allophone strobe input
dac_out, // 1-bit PWM DAC output
);
//////////// CLOCK //////////
input clk;
//////////// RESET, ACTIVE LOW //////////
input rst_an;
//////////// OUTPUTS //////////
output dac_out;
output ldq;
//////////// INPUTS //////////
input [5:0] data_in;
input data_stb;
// internal counter and data registers
wire pwmdac_ack, src_strobe;
wire signed [15:0] sig_source;
wire signed [15:0] sig_filter;
wire period_done;
wire [7:0] period;
wire [7:0] dur;
wire [15:0] amp;
wire signed [7:0] coef_bus;
wire coef_load;
wire done;
SOURCE u_source (
.clk (clk),
.rst_an (rst_an),
.period (period),
.amplitude (amp[14:0]),
.strobe (src_strobe),
.period_done (period_done),
.source_out (sig_source)
);
FILTER u_filter (
.clk (clk),
.rst_an (rst_an),
.coef_in ({coef_bus, 1'b0}),
.coef_load (coef_load),
.sig_in (sig_source),
.sig_out (sig_filter),
.start (pwmdac_ack),
.done (src_strobe)
);
PWMDAC u_pwmdac (
.clk (clk),
.rst_an (rst_an),
.din (sig_filter[15:8]),
.din_ack (pwmdac_ack),
.dacout (dac_out)
);
CONTROLLER u_controller (
.clk (clk),
.rst_an (rst_an),
.ldq (ldq),
.data_in (data_in),
.data_stb (data_stb),
.period_out (period),
.amp_out (amp),
.coeff_out (coef_bus),
.coeff_stb (coef_load),
.period_done_in (period_done)
);
always @(posedge clk, negedge rst_an)
begin
if (rst_an == 0)
begin
// reset values
end
else
begin
// clocked process
end
end
endmodule

View File

@ -0,0 +1,53 @@
//
// PWMDAC testbench
//
// Niels Moseley - Moseley Instruments 2017
// http://www.moseleyinstruments.com
//
module SPEECH256_TOP_TB;
reg clk, rst_an;
reg [5:0] data_in;
reg data_stb;
wire ldq,dac_out;
SPEECH256_TOP u_speech256_top (
.clk (clk),
.rst_an (rst_an),
.ldq (ldq),
.data_in (data_in),
.data_stb (data_stb),
.dac_out (dac_out)
);
integer fd; // file descriptor
initial
begin
fd = $fopen("dacout.sw","wb");
$dumpfile ("speech256_top.vcd");
$dumpvars;
clk = 0;
rst_an = 0;
data_stb = 0;
#5
rst_an = 1;
#5
data_in = 6;
data_stb = 1;
#5
data_stb = 0;
#300000
//$fclose(fd);
$finish;
end
always @(posedge clk)
begin
$fwrite(fd,"%u", {31'd0,dac_out});
end
always
#5 clk = !clk;
endmodule