diff --git a/examples/pcmtest.pas b/examples/pcmtest.pas
new file mode 100644
index 0000000..423faaf
--- /dev/null
+++ b/examples/pcmtest.pas
@@ -0,0 +1,47 @@
+{$H1536}
+program pcmtest;
+uses pcmaudio;
+
+var filename:string;
+ buf:SndBufPtr;
+ f:file;
+ size:integer;
+ i:integer;
+ c:char;
+ sampleRate:integer;
+ err:integer;
+begin
+ if ParamCount > 0 then
+ filename := ParamStr(1)
+ else
+ begin
+ write('Filename> ');
+ readln(filename);
+ end;
+
+ err := 1;
+ if ParamCount > 1 then
+ val(ParamStr(2),sampleRate, err);
+
+ if err <> 0 then
+ sampleRate := 16000;
+
+ open(f, filename, ModeReadOnly);
+ size := FileSize(f);
+ new(buf, size);
+
+ buf^ := '';
+ write('Reading ', size, ' bytes...');
+ for i := 1 to size do
+ begin
+ read(f,c);
+ AppendChar(buf^,c);
+ end;
+ writeln;
+
+ close(f);
+
+ PlaySample(buf, sampleRate);
+
+ dispose(buf);
+end.
diff --git a/examples/pcmtest2.pas b/examples/pcmtest2.pas
new file mode 100644
index 0000000..56ecb95
--- /dev/null
+++ b/examples/pcmtest2.pas
@@ -0,0 +1,60 @@
+{$H1536}
+program pcmtest2;
+uses pcmaudio;
+
+var filename:string;
+ buf:SndBufPtr;
+ f:file;
+ size:integer;
+ i:integer;
+ c:char;
+ sampleRate:integer;
+ err:integer;
+ done:boolean;
+begin
+ if ParamCount > 0 then
+ filename := ParamStr(1)
+ else
+ begin
+ write('Filename> ');
+ readln(filename);
+ end;
+
+ err := 1;
+ if ParamCount > 1 then
+ val(ParamStr(2), sampleRate, err);
+ if err > 0 then
+ sampleRate := 16000;
+
+ open(f, filename, ModeReadOnly);
+ size := FileSize(f);
+ new(buf, size);
+
+ buf^ := '';
+ write('Reading ', size, ' bytes...');
+ for i := 1 to size do
+ begin
+ read(f,c);
+ AppendChar(buf^,c);
+ end;
+ writeln;
+
+ close(f);
+
+ SampleQStart(buf, sampleRate);
+
+ write('Press Q to stop> ');
+ done := false;
+ while not done do
+ begin
+ read(c);
+ if upcase(c) = 'Q' then
+ done := true
+ else
+ writeln('Queue size: ', SampleQSize);
+ end;
+
+ SampleQStop;
+
+ dispose(buf);
+end.
diff --git a/lib/pcmaudio.inc b/lib/pcmaudio.inc
new file mode 100644
index 0000000..4c3cdb3
--- /dev/null
+++ b/lib/pcmaudio.inc
@@ -0,0 +1,7 @@
+type SndBuf = string[32768];
+type SndBufPtr = ^SndBuf;
+
+procedure PlaySample(buf:SndBufPtr;sampleRate:integer); external;
+procedure SampleQStart(buf:SndBufPtr;sampleRate:integer); external;
+procedure SampleQStop; external;
+function SampleQSize:integer; external;
diff --git a/lib/pcmaudio.s b/lib/pcmaudio.s
new file mode 100644
index 0000000..a030985
--- /dev/null
+++ b/lib/pcmaudio.s
@@ -0,0 +1,241 @@
+ .EQU AUDIO_BASE $A00
+ .EQU IRQC_REG $980
+ .EQU IRQC_EN $80
+
+; args: sample rate
+START_PCMAUDIO:
+ ; calculate clock divider
+ LOADCP 77000000
+ SWAP
+ LOADCP _DIV
+ CALL
+
+ LOADC AUDIO_BASE + 1
+ SWAP ; put clock divider on ToS
+; LOADCP 4812 ; clock divider for 16KHz sample rate
+; LOADCP 2406 ; clock divider for 32KHz sample rate
+ STOREI 1
+ LOADCP 32768 ; set amplitude to biased 0
+ STOREI
+ DROP
+ LOADC AUDIO_BASE
+ LOADC 17 ; enable channel, enable interrupt
+ STOREI
+ DROP
+ RET
+
+STOP_AUDIO:
+ LOADC AUDIO_BASE
+ LOADC 0
+ STOREI
+ DROP
+ RET
+
+; args: pointer to pascal string, sample rate
+ .EQU PS_PTR 0
+ .EQU PS_COUNT 4
+ .EQU PS_FS 12
+PLAYSAMPLE:
+ FPADJ -PS_FS
+
+ LOADCP START_PCMAUDIO
+ CALL
+
+ DUP
+ LOADI ; get string size from header
+ SHR ; divide by 4 to get word count
+ SHR
+
+ STORE PS_COUNT
+ INC 8 ; skip rest of header
+ STORE PS_PTR ; store sample data pointer
+
+PS_L0:
+ LOAD PS_PTR ; load pointer
+ INC.S1.X2Y 4 ; increment and keep old value
+ STORE PS_PTR ; store incremented value
+
+ LOADI ; load 32 bit word
+ DUP
+ BROT ; get upper 16 bit word
+ BROT
+ LOADCP $FFFF
+ AND
+
+ LOADCP PLAY_1SAMPLE
+ CALL
+
+ LOADCP $FFFF ; get lower 16 bit word
+ AND
+ LOADCP PLAY_1SAMPLE
+ CALL
+
+ LOAD PS_COUNT ; load word count
+ DEC 1 ; decrement
+ DUP
+ STORE PS_COUNT
+ CBRANCH.NZ PS_L0 ; loop if not zero
+
+ LOADCP STOP_AUDIO
+ CALL
+
+ FPADJ PS_FS
+ RET
+
+; play one sample, waiting
+; for the clock divider, which
+; is visible via the phase flag
+; args: 16-bit unsigned sample
+PLAY_1SAMPLE:
+
+PLAY1_L0:
+ LOADC AUDIO_BASE
+ LOADI
+ LOADC 8 ; get fifo_full flag
+ AND
+ CBRANCH.NZ PLAY1_L0 ; loop if fifo is full
+
+ LOADC AUDIO_BASE+2 ; store amplitude value
+ SWAP
+ STOREI
+ DROP
+ RET
+
+; start interrupt-driven sample playback
+; args: pointer to pascal string, sample rate
+SAMPLEQSTART:
+ LOADCP START_PCMAUDIO
+ CALL
+
+ LOADCP SMPLQ_COUNT
+ OVER
+ LOADI ; get string size from header
+ SHR ; divide by 4 to get word count
+ SHR
+
+ STOREI
+ DROP
+
+ LOADCP SMPLQ_PTR
+ SWAP
+ INC 8 ; skip rest of header
+ STOREI ; store sample data pointer
+ DROP
+
+ LOADCP SMPLQ_ISR ; set interrupt handler
+ STOREREG IV
+
+ LOADC IRQC_REG ; enable irq
+ LOADC IRQC_EN
+ STOREI
+ DROP
+
+ RET
+
+SAMPLEQSTOP:
+ LOADCP SMPLQ_PTR
+ LOADC 0
+ STOREI
+ DROP
+
+ LOADCP STOP_AUDIO
+ CALL
+
+ LOADC IRQC_REG ; disable irq
+ LOADC 0
+ STOREI
+ DROP
+ RET
+
+SAMPLEQSIZE:
+ LOADCP SMPLQ_COUNT
+ LOADI
+ RET
+
+SMPLQ_PTR: .WORD 0
+SMPLQ_COUNT: .WORD 0
+
+SMPLQ_ISR:
+ LOADC IRQC_REG
+ LOADI
+ LOADC 4 ; check for audio interrupt
+ AND
+ CBRANCH.Z SMPLQ_I_XT ; if flag not set, exit
+
+SMPLQ_I_L:
+ LOADCP SMPLQ_PTR
+ LOADI ; load word pointer
+ DUP
+ CBRANCH.NZ SMPLQ_I_B ; check for null pointer
+ DROP
+ BRANCH SMPLQ_I_XT ; if null, end interrupt routine
+SMPLQ_I_B:
+ LOADI ; load next word
+ DUP
+
+ BROT ; get high half-word
+ BROT
+ LOADCP $FFFF
+ AND
+
+ LOADC AUDIO_BASE+2
+ SWAP
+ STOREI ; write sample, keep addr
+
+ SWAP ; addr to NoS, lower halfword on ToS
+ LOADCP $FFFF
+ AND
+ STOREI ; write sample
+ DROP
+
+ ; decrement word count
+ LOADCP SMPLQ_COUNT
+ LOADI.S1.X2Y ; load counter, keep addr
+ DEC 1
+ DUP
+ CBRANCH.Z SMPLQ_I_END ; end if zero
+
+ STOREI ; store new counter value
+ DROP
+
+ ; increment pointer
+ LOADCP SMPLQ_PTR
+ LOADI.S1.X2Y
+ INC 4
+ STOREI
+ DROP
+
+ ; check if fifo is full
+ LOADC AUDIO_BASE
+ LOADI
+ LOADC 8 ; fifo_full
+ AND
+ CBRANCH.Z SMPLQ_I_L ; next sample if not full
+
+ LOADC AUDIO_BASE
+ LOADC 17 ; re-enable channel interrupt
+ STOREI
+ DROP
+
+ BRANCH SMPLQ_I_XT
+
+ ; end playback, set ptr and counter to zero
+SMPLQ_I_END:
+ DROP
+ DROP
+ LOADCP SMPLQ_PTR
+ LOADC 0
+ STOREI
+ DROP
+ LOADCP SMPLQ_COUNT
+ LOADC 0
+ STOREI
+ DROP
+
+SMPLQ_I_XT:
+ LOADC IRQC_REG ; re-enable interrupts
+ LOADC IRQC_EN
+ STOREI
+ DROP
+ LOADREG IR ; jump via interrupt return register
+ JUMP
diff --git a/lib/runtime.s b/lib/runtime.s
index ce60b8d..9eb35d7 100644
--- a/lib/runtime.s
+++ b/lib/runtime.s
@@ -1931,6 +1931,12 @@ _CLEARESTACK_XT:
; Terminate program: clear estack and
; jump to coreloader
PTERM:
+ ; just to be safe, disable interrupts
+ LOADC $980
+ LOADC 0
+ STOREI
+ DROP
+
LOADCP _CLEARESTACK
CALL
LOADCP LOADER_START
diff --git a/lib/stdlib.pas b/lib/stdlib.pas
index dd6294c..84025b3 100644
--- a/lib/stdlib.pas
+++ b/lib/stdlib.pas
@@ -1844,6 +1844,8 @@ end;
function filesize(var fil:file):integer;
begin
+ checkerror(fil);
+
if fil.typ = IOChannel then
filesize := -1
else
diff --git a/tridoracpu/tridoracpu.srcs/tdraudio.v b/tridoracpu/tridoracpu.srcs/tdraudio.v
index b9ecc94..0cc055e 100644
--- a/tridoracpu/tridoracpu.srcs/tdraudio.v
+++ b/tridoracpu/tridoracpu.srcs/tdraudio.v
@@ -42,12 +42,12 @@ module wavegen #(DATA_WIDTH=32, CLOCK_DIV_WIDTH=22,
assign fifo_rd_en = (div_count == 0) && channel_enable && ~fifo_empty;
assign fifo_wr_en = wr_en && (reg_sel == TDRAU_REG_AMP);
- reg irq_buf, irq_done;
- assign irq = irq_buf;
+ reg irq_buf, irq_enable;
+ assign irq = channel_enable && irq_buf;
reg [DATA_WIDTH-1:0] rd_data_buf;
assign rd_data = rd_data_buf;
- // assign rd_data = {{DATA_WIDTH-8{1'b0}}, {4{1'b0}}, fifo_full, fifo_empty, amp_phase, channel_enable};
+
assign amp_val = amp_out;
assign running = channel_enable;
@@ -56,7 +56,8 @@ module wavegen #(DATA_WIDTH=32, CLOCK_DIV_WIDTH=22,
/* update read data buffer */
always @(posedge clk)
begin
- rd_data_buf <= {{DATA_WIDTH-8{1'b0}}, {4{1'b0}}, fifo_full, fifo_empty, amp_phase, channel_enable};
+ rd_data_buf <= {{DATA_WIDTH-8{1'b0}},
+ {3{1'b0}}, irq_enable, fifo_full, fifo_empty, amp_phase, channel_enable};
end
/* irq signal to interrupt controller */
@@ -65,23 +66,23 @@ module wavegen #(DATA_WIDTH=32, CLOCK_DIV_WIDTH=22,
if(reset)
irq_buf <= 0;
else
- if(fifo_empty && ~irq_done)
+ if(fifo_empty && irq_enable)
irq_buf <= 1;
else
irq_buf <= 0;
end
- /* interrupt done flag, used to ensure the irq signal is set for just one clock tick */
+ /* interrupt enable flag */
always @(posedge clk)
begin
if(reset)
- irq_done <= 0;
+ irq_enable <= 0;
else
- if(rd_en) // reset irq done flag on any register read
- irq_done <= 0;
+ if(ctl_reg_write)
+ irq_enable <= wr_data[4];
else
if(irq_buf)
- irq_done <= 1;
+ irq_enable <= 0; // disable interrupts after an interrupt
end
/* channel enable flag */
@@ -139,8 +140,8 @@ module wavegen #(DATA_WIDTH=32, CLOCK_DIV_WIDTH=22,
amp_out <= AMP_BIAS;
// reset phase bit when enabling the channel
- if (ctl_reg_write && wr_data[0])
- // when channel is enabled, phase will be flipped on next tick
+ if (ctl_reg_write && wr_data[0] && ~channel_enable)
+ // when channel is being enabled, phase will be flipped on next tick
// because div_count will become zero
amp_phase <= 1;
end
@@ -232,9 +233,6 @@ module tdraudio #(DATA_WIDTH=32) (
chan3_amp,
chan3_running, chan3_irq);
- reg irq_out_buf;
- assign irq_out = irq_out_buf;
-
reg [DAC_WIDTH:0] deltasigma_acc; // one extra bit
wire [DAC_WIDTH:0] amp_sum = chan0_amp + chan1_amp + chan2_amp + chan3_amp; // also one overflow bit here
assign gain_sel = 1; // gain select: 0 -> 12dB, 1 -> 6dB
@@ -242,6 +240,9 @@ module tdraudio #(DATA_WIDTH=32) (
// assign shutdown_n = running;
assign shutdown_n = 1; /* don't enable shutdown mode, it creates a mains hum */
+ reg irq_out_buf;
+ assign irq_out = irq_out_buf;
+
always @(posedge clk) irq_out_buf <= chan0_irq || chan1_irq || chan2_irq || chan3_irq;
/* delta-sigma DAC */
diff --git a/tridoracpu/tridoracpu.xpr b/tridoracpu/tridoracpu.xpr
index 3b60ca9..3767063 100644
--- a/tridoracpu/tridoracpu.xpr
+++ b/tridoracpu/tridoracpu.xpr
@@ -378,16 +378,18 @@
-
+
-
- Includes alternate algorithms for timing-driven optimization
+
+ Similar to Performance_ExplorePostRoutePhysOpt, but enables logic optimization step (opt_design) with the ExploreWithRemap directive.
-
+
+
+
-
+
@@ -395,8 +397,11 @@
+
+
+
+
-