diff --git a/doc/irqctrl.md b/doc/irqctrl.md index bf76999..580c123 100644 --- a/doc/irqctrl.md +++ b/doc/irqctrl.md @@ -9,13 +9,12 @@ The interrupt controller uses a single register at address: $980 |_bit_ |15|14|13|12|11|10|09|08|07|06|05|04|03|02|01|00| |- |- |- |- |- |- |- |- |- |- |- |- |- |- |- |- |- | -|_Value_|t |t |t |t |t |t |t |t |- |- |- |- |- |p2 |p1 |p0 | +|_Value_|t |t |t |t |t |t |t |t |- |- |- |- |- |- |p1 |p0 | |Bitfields|Description| |---------|-----------| | _t_ | unsigned 24 bit counter of timer ticks since reset -| _p2_ | IRQ 2 (audio) interrupt pending if 1 | _p1_ | IRQ 1 (timer tick) interrupt pending if 1 | _p0_ | IRQ 0 (UART) interrupt pending if 1 diff --git a/doc/tdraudio.md b/doc/tdraudio.md deleted file mode 100644 index 999ebfc..0000000 --- a/doc/tdraudio.md +++ /dev/null @@ -1,104 +0,0 @@ -# Audio Controller -The audio controller provides four channels of 16-bit PCM audio playback. - -It uses multiple registers starting at address $A00. - -Each of the four channels has three registers. - -For the first channel the register addresses are: - -|Address|Description| -|-------|-----------| -| $A00 | Control Register | -| $A01 | Clock Divider Register | -| $A02 | Amplitude Register | - -The register addresses for the second channel start at $A04, -the third channel at $A08 -and the fourth channel at $A0C. - -## Reading the control register - -|_bit_ |31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16| -|- |- |- |- |- |- |- |- |- |- |- |- |- |- |- |- |- | -|_Value_|- |- |- |- |- |- |- |- |- |-|- |- |- |- |- |- | - -|_bit_ |15|14|13|12|11|10|09|08|07|06|05|04|03|02|01|00| -|- |- |- |- |- |- |- |- |- |- |- |- |- |- |- |- |- | -|_Value_|- |- |- |- |- |- |- |- |- |- |- |i |f | e | p | c | - - -|Bitfields|Description| -|---------|-----------| -| _i_ | interrupt is enabled for this channel when 1 | -| _f_ | sample buffer is full when 1 | -| _e_ | sample buffer is empty when 1 | -| _p_ | changes from 0 to 1 and vice versa on each sample clock | -| _c_ | channel is enabled if 1 | - -## Writing the control register - -|_bit_ |31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16| -|- |- |- |- |- |- |- |- |- |- |- |- |- |- |- |- |- | -|_Value_|- |- |- |- |- |- |- |- |- |-|- |- |- |- |- |- | - -|_bit_ |15|14|13|12|11|10|09|08|07|06|05|04|03|02|01|00| -|- |- |- |- |- |- |- |- |- |- |- |- |- |- |- |- |- | -|_Value_|- |- |- |- |- |- |- |- |- |- |- |i |- | - | - | c | - - -|Bitfields|Description| -|---------|-----------| -| _c_ | enable channel if 1, disable if 0 | -| _i_ | enable channel interrupt if 1, disable if 0 | - - -## Writing the clock divider register - -|_bit_ |31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16| -|- |- |- |- |- |- |- |- |- |- |- |- |- |- |- |- |- | -|_Value_|d |d |d |d |d |d |d |d |d |d|d |d |d |d |d |d | - -|_bit_ |15|14|13|12|11|10|09|08|07|06|05|04|03|02|01|00| -|- |- |- |- |- |- |- |- |- |- |- |- |- |- |- |- |- | -|_Value_|d |d |d |d |d |d |d |d |d |d|d |d |d |d |d |d | - - -|Bitfields|Description| -|---------|-----------| -| _d_ | an unsigned 32-bit value for the clock divider | - - -## Writing the amplitude register - -|_bit_ |31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16| -|- |- |- |- |- |- |- |- |- |- |- |- |- |- |- |- |- | -|_Value_|- |- |- |- |- |- |- |- |- |-|- |- |- |- |- |- | - -|_bit_ |15|14|13|12|11|10|09|08|07|06|05|04|03|02|01|00| -|- |- |- |- |- |- |- |- |- |- |- |- |- |- |- |- |- | -|_Value_|a |a |a |a |a |a |a |a |a |a |a |a |a | a | a | a | - - -|Bitfields|Description| -|---------|-----------| -| _a_ | an unsigned 16-bit value for the amplitude (sample) value with a bias of 32768 | - -## Notes -The clock divider specifies the number of CPU clock ticks between two samples. - -Writing to the amplitude register adds the sample value to the sample buffer. The sample buffer is organized as a FIFO with 16 elements. - -Amplitude (sample) values are represented as unsigned, biased 16-bit numbers. The bias is 32768, so given an amplitude range of 1.0 to -1.0, a 1.0 is represented by 65535, 0.0 by 32768 and -1.0 by 0. - -Interrupt processing needs to be enabled for each channel if required. - -An interrupt on any channel will be signalled to the interrupt controller -as IRQ 2. The interrupt service routine should check all running channels -for an emtpy buffer. - -If an audio interrupt has occured on a channel, the interrupt enable flag -is cleared for that channel. It needs to be re-enabled in the interrupt service routine. - -Interrupts also need to be enabled on the interrupt controller, -and re-enabled there after each interrupt. diff --git a/examples/pcmtest.pas b/examples/pcmtest.pas deleted file mode 100644 index 423faaf..0000000 --- a/examples/pcmtest.pas +++ /dev/null @@ -1,47 +0,0 @@ -{$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 deleted file mode 100644 index 56ecb95..0000000 --- a/examples/pcmtest2.pas +++ /dev/null @@ -1,60 +0,0 @@ -{$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 deleted file mode 100644 index 4c3cdb3..0000000 --- a/lib/pcmaudio.inc +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index a030985..0000000 --- a/lib/pcmaudio.s +++ /dev/null @@ -1,241 +0,0 @@ - .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 9eb35d7..ce60b8d 100644 --- a/lib/runtime.s +++ b/lib/runtime.s @@ -1931,12 +1931,6 @@ _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 84025b3..dd6294c 100644 --- a/lib/stdlib.pas +++ b/lib/stdlib.pas @@ -1844,8 +1844,6 @@ 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 0cc055e..b9ecc94 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_enable; - assign irq = channel_enable && irq_buf; + reg irq_buf, irq_done; + assign irq = 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,8 +56,7 @@ 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}}, - {3{1'b0}}, irq_enable, fifo_full, fifo_empty, amp_phase, channel_enable}; + rd_data_buf <= {{DATA_WIDTH-8{1'b0}}, {4{1'b0}}, fifo_full, fifo_empty, amp_phase, channel_enable}; end /* irq signal to interrupt controller */ @@ -66,23 +65,23 @@ module wavegen #(DATA_WIDTH=32, CLOCK_DIV_WIDTH=22, if(reset) irq_buf <= 0; else - if(fifo_empty && irq_enable) + if(fifo_empty && ~irq_done) irq_buf <= 1; else irq_buf <= 0; end - /* interrupt enable flag */ + /* interrupt done flag, used to ensure the irq signal is set for just one clock tick */ always @(posedge clk) begin if(reset) - irq_enable <= 0; + irq_done <= 0; else - if(ctl_reg_write) - irq_enable <= wr_data[4]; + if(rd_en) // reset irq done flag on any register read + irq_done <= 0; else if(irq_buf) - irq_enable <= 0; // disable interrupts after an interrupt + irq_done <= 1; end /* channel enable flag */ @@ -140,8 +139,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] && ~channel_enable) - // when channel is being enabled, phase will be flipped on next tick + if (ctl_reg_write && wr_data[0]) + // when channel is enabled, phase will be flipped on next tick // because div_count will become zero amp_phase <= 1; end @@ -233,6 +232,9 @@ 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 @@ -240,9 +242,6 @@ 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 3767063..3b60ca9 100644 --- a/tridoracpu/tridoracpu.xpr +++ b/tridoracpu/tridoracpu.xpr @@ -378,18 +378,16 @@ - + - - Similar to Performance_ExplorePostRoutePhysOpt, but enables logic optimization step (opt_design) with the ExploreWithRemap directive. + + Includes alternate algorithms for timing-driven optimization - - - + - + @@ -397,11 +395,8 @@ - - - - +