diff --git a/LICENSE.md b/LICENSE.md
index 6392510..3755dbb 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -4,7 +4,7 @@ All files, except where explicitly stated otherwise, are licensed according to t
------------------------------------------------------------------------------
-Copyright 2024-2026 Sebastian Lederer
+Copyright 2024 Sebastian Lederer
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
diff --git a/README.md b/README.md
index fe930a7..be77d37 100644
--- a/README.md
+++ b/README.md
@@ -41,25 +41,6 @@ Other inspirations were, among others, in no particular order:
- the Magic-1 by Bill Buzbee
- the OPC by revaldinho
-## October 2025 Update
-This update introduces a data cache for the Tridora-CPU. It is similar to the instruction cache
-as it caches the 16 bytes coming from the DRAM memory controller. It is a write-back cache, i.e.
-when a word inside the cached area is written, it updates the cache instead of invalidating it.
-
-This is important because there are many idioms in the stack machine assembly language where you
-store a local variable and then read it again (e.g. updating a loop variable).
-
-Since for most programs, the user stack and parts of the heap are inside the DRAM area, the data cache
-has a more noticable impact. In the benchmark program that was already used for the last update,
-the data cache results in a 50% improvement for the empty loop test. This is in comparison to the version
-without data cache but with the instruction cache, both running code out of DRAM.
-
-It is also noticable for compile times: With the data cache, compiling and assembling the
-"hello,world" program takes 16 seconds instead of 20. With a little tweak of the SD-Card controller
-that slightly increased the data transfer rate, the build time goes down to 15 seconds.
-
-Also, an audio controller was added that allows interrupt-driven sample playback via an AMP2 PMOD.
-
## April 2025 Update
The clock has been reduced to 77 MHz from 83 MHz. Apparently the design was at the limit and
timing problems were cropping up seemingly at random. Reducing the clock speed made some
@@ -81,7 +62,7 @@ on the emulator image.
- the [Hackaday project](https://hackaday.io/project/198324-tridora-cpu) (mostly copy-paste from this README)
- the [YouTube channel](https://www.youtube.com/@tridoracpu/videos) with some demo videos
- the [emulator](https://git.insignificance.de/slederer/-/packages/generic/tridoraemu/0.0.5/files/12) (source and windows binary)
-- the [FPGA bitstream](https://git.insignificance.de/slederer/-/packages/generic/tdr-bitstream/0.0.4/files/16) for the Arty-A7-35T board
+- the [FPGA bitstream](https://git.insignificance.de/slederer/-/packages/generic/tdr-bitstream/0.0.2/files/14) for the Arty-A7-35T board
- an [SD-card image](https://git.insignificance.de/slederer/-/packages/generic/tdr-cardimage/0.0.4/files/13)
Contact the author here: tridoracpu [at] insignificance.de
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/mem.md b/doc/mem.md
index 29177b2..e24fbe2 100644
--- a/doc/mem.md
+++ b/doc/mem.md
@@ -22,12 +22,11 @@ The _BSEL_ and _BPLC_ instructions are designed to assist with accessing bytes w
The byte ordering is big-endian.
## Accessing the I/O Area
-The I/O area uses the same word addressing in increments of four to access the registers of the I/O controllers. In practice, only the VGA framebuffer controller and the audio controller use multiple registers.
-For the other controllers, there is a single 32 bit register that is repeated all over the address space of the corresponding I/O slot.
+The I/O area organizes memory slightly different. Here, pointing out individual bytes is not very useful, so the I/O controllers use register addresses with increments of one. In practice, there is only the VGA framebuffer controller which uses multiple registers.
The individual I/O controllers each have a memory area of 128 bytes, so there is a maximum number of 16 I/O controllers.
-Currently, only I/O slots 0-4 are being used.
+Currently, only I/O slots 0-3 are being used.
|I/O slot| Address | Controller |
|--------|---------|------------|
@@ -35,4 +34,3 @@ Currently, only I/O slots 0-4 are being used.
| 1 | $880 | SPI-SD |
| 2 | $900 | VGA |
| 3 | $980 | IRQC |
-| 4 | $A00 | TDRAUDIO |
diff --git a/doc/pascalprogramming.md b/doc/pascalprogramming.md
index 454b46b..df5d3fd 100644
--- a/doc/pascalprogramming.md
+++ b/doc/pascalprogramming.md
@@ -235,85 +235,6 @@ In Wirth Pascal, labels must be numbers. Other Pascal dialects also allow normal
Tridora-Pascal only allows identifiers as labels.
-## Units
-Units are the method to create libraries in Tridora-Pascal, that is, codes module that can
-be reused in other programs.
-
-Tridora-Pascal follows the unit syntax that has been established in UCSD-Pascal and is also
-used in Turbo Pascal.
-
-Units are imported with the *USES* keyword, right after the *PROGRAM* statement.
-Multiple units can be imported by separating the unit names with commas.
-
-There are some differences: In Tridora-Pascal, the unit file does not contain the interface
-section, only the implementation section. The interface section is instead placed into a
-separate file with the extension *.inc*, without any *UNIT* or *INTERFACE* keywords.
-
-This file will be included by the compiler and should contain
-procedure or function declarations (as *EXTERNAL*). It can also contain *TYPE*,
-*CONST* and *VAR* statements.
-
-All Pascal symbols of the unit are imported into the main program. There
-is no separate namespace for units.
-
-### Using an Existing Unit
-An existing unit is imported with the *USES* statement that must be placed
-immediately after the *PROGRAM* statement.
-
-The compiler will look for an include file with the unit name and an *.inc* extension.
-It will also
-tell the assembler to include an assembly language file for each
-unit. The filename must be the unit name plus an *.s* extension.
-
-Since there is no linker in Tridora-Pascal, all imported units will be
-assembled together with the main program.
-
-The compiler looks for unit *.inc* and *.s* files in the current volume or
-in the *SYSTEM* volume.
-
-### Compiling a Unit
-A unit implementation file should start with a *UNIT* statement instead of a *PROGRAM*
-statement.
-
-It should be compiled, not assembled.
-
-When building a program that uses units, the assembler will include an assembly language
-file for each unit.
-
-It is possible to write units in assembly language. This is done by
-directly providing the *.s* file and creating an *.inc* file with
-the *EXTERNAL* declarations matching the assembly language
-file.
-#### Example
-```pascal
-(* UnitExamples.pas *)
-program UnitExample;
-uses hello;
-
-begin
- sayHello('unit');
-end.
-```
-
-#### Example Unit Implementation File
-```pascal
-(* hello.pas *)
-unit hello;
-
-implementation
-
-procedure sayHello(s:string);
-begin
- writeln('hello, ', s);
-end;
-
-end.
-```
-#### Example Unit Include File
-```pascal
-(* hello.inc *)
-procedure sayHello(s:string); external;
-```
## Compiler Directives
Tridora-Pascal understands a small number of compiler directives which are introduced as usual with a comment and a dollar-sign. Both comment styles can be used.
diff --git a/doc/tdraudio.md b/doc/tdraudio.md
deleted file mode 100644
index 5d8b22f..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 |
-| $A04 | Clock Divider Register |
-| $A08 | Amplitude Register |
-
-The register addresses for the second channel start at $A10,
-the third channel at $A20
-and the fourth channel at $A30.
-
-## 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/doc/uart.md b/doc/uart.md
index 6a6d191..b349eb4 100644
--- a/doc/uart.md
+++ b/doc/uart.md
@@ -37,7 +37,7 @@ It uses a fixed serial configuration of 115200 bps, 8 data bits, 1 stop bit, no
## Notes
-A 64 byte FIFO is used when receiving data.
+A 16 byte FIFO is used when receiving data.
When reading data, each byte needs to be acknowledged by writing the _C_ flag to the UART register.
diff --git a/doc/vga.md b/doc/vga.md
index 76520f2..b53f56d 100644
--- a/doc/vga.md
+++ b/doc/vga.md
@@ -4,16 +4,13 @@ Registers
|Name|Address|Description|
|----|-------|-----------|
|_FB_RA_ | $900 | Read Address |
-|_FB_WA_ | $904 | Write Address |
-| _FB_IO_ | $908 | I/O Register |
-| _FB_PS_ | $90C | Palette Select |
-| _FB_PD_ | $910 | Palette Data |
-| _FB_CTL_ | $914 | Control Register |
-| _FB_SHIFTER | $918 | Shift Assist Register |
-| _FB_SHIFTCOUNT | $91C | Shift Count Register |
-| _FB_SHIFTERM | $920 | Shifted Mask Register |
-| _FB_SHIFTERSP | $924 | Shifter Spill Register |
-| _FB_MASKGEN | $928 | Mask Generator Register |
+|_FB_WA_ | $901 | Write Address |
+| _FB_IO_ | $902 | I/O Register |
+| _FB_PS_ | $903 | Palette Select |
+| _FB_PD_ | $904 | Palette Data |
+| _FB_CTL_ | $905 | Control Register |
+
+
## Pixel Data
Pixel data is organized in 32-bit-words. With four bits per pixel, one word
@@ -84,54 +81,3 @@ The control register contains status information. It can only be read.
The _m_ field indicates the current graphics mode. At the time of writing, it is
always 1 which denotes a 640x400x4 mode.
The _vb_ bit is 1 when the video signal generator is in its vertical blank phase.
-
-## Shift Assist Register
-The *shift assist register* can be used to accelerate shifting pixel/bitmap data.
-Writing a word of pixel data to this register initialises the shifting process.
-
-After writing to the shift count register (see below), reading the shift assist
-register retrieves the shifted pixel data.
-
-Writing to the shift assist register will reset the shift count.
-
-## Shift Count Register
-Writing a number from 0-7 to the *shift count register* triggers shifting the
-contents of the shift assist register. Pixel data is shifted by four bits
-to the right times the shift count. Bits 31-3 of the shift count are ignored, so you can
-directly write a horizontal screen coordinate to the register.
-
-This register cannot be read.
-
-## Shifter Mask Register
-The *shifter mask register* contains the shifted pixel data converted into
-a mask. See the *mask generator register* for an
-explanation of the mask.
-
-## Shifter Spill Register
-The *shifter spill register* contains the pixel data that has
-been shifted out to the right. For example, if the shift count is two,
-the spill register contains the two rightmost pixels (bits 7-0) of
-the original pixel data, placed into the two topmost pixels (bits 31-24).
-
-The rest of the register is set to zero.
-
-## Mask Generator Register
-The *mask generator register* creates a mask from pixel data.
-For each four bits of a pixel, the corresponding four mask bits
-are all set to one if the pixel value is not zero.
-
-This can be used to combine foreground and background pixel data
-with a pixel value of zero for a transparent background color.
-
-Usually, the mask will be inverted with a *NOT* instruction
-to clear all pixels in the background that are set in the foreground
-with an *AND* instruction
-before *ORing* foreground and background together.
-
-Example in hexadecimal, each digit is a pixel:
-| Pixel Data | Mask |
-|------------|------|
-| $00000000 | $00000000 |
-| $00000001 | $0000000F |
-| $0407000F | $0F0F000F |
-| $1234ABC0 | $FFFFFFF0 |
diff --git a/examples/fastfire.inc b/examples/fastfire.inc
deleted file mode 100644
index bf0dce6..0000000
--- a/examples/fastfire.inc
+++ /dev/null
@@ -1,5 +0,0 @@
-const FIREWIDTH = 319; FIREHEIGHT = 79; (* keep in sync with fastfire.s! *)
-type FireBuf = array [0..FIREHEIGHT, 0..FIREWIDTH] of integer;
-
-procedure FastFireUpdate(var f:FireBuf); external;
-procedure FastFireDraw(var f:FireBuf;screenx, screeny:integer); external;
diff --git a/examples/fastfire.s b/examples/fastfire.s
deleted file mode 100644
index 63ace51..0000000
--- a/examples/fastfire.s
+++ /dev/null
@@ -1,326 +0,0 @@
- ; width and height of the fire cell matrix
- ; Be sure to sync this with fastfire.inc!
- .EQU FIREWIDTH 319
- .EQU FIREHEIGHT 79
-
- ;
- ; The cell matrix actually has one column
- ; and one row more than FIREWIDTH and
- ; FIREHEIGHT to handle the negative
- ; X offsets when calculating new
- ; cell values.
- ; Likewise, there is one more row.
- ; So rows are processed from 0 to FIREHEIGHT - 2
- ; and columms from 1 to FIREWIDTH - 1.
-
- ; cells considered for calculating new
- ; value for cell O (reference cells):
- ; .....O......
- ; ....123.....
- ; .....4......
-
-; args: pointer to fire cell buffer
- .EQU FF_ROW_COUNT 0
- .EQU FF_COL_COUNT 4
- .EQU FF_ROW_OFFS 8
- .EQU FF_OFFS1 12
- .EQU FF_OFFS2 16
- .EQU FF_OFFS3 20
- .EQU FF_OFFS4 24
- .EQU FF_CELL_PTR 28
- .EQU FF_FS 32
-FASTFIREUPDATE:
- FPADJ -FF_FS
- STORE FF_CELL_PTR
- LOADC FIREHEIGHT-1
- STORE FF_ROW_COUNT
-
- ; calculate offsets for reference cells
- LOADC FIREWIDTH+1
- SHL 2
- DUP
- STORE FF_ROW_OFFS ; offset to next row: WIDTH*4
- DEC 4 ; offset to cell 1: row offset - 4
- DUP
- STORE FF_OFFS1
- INC 4
- DUP
- STORE FF_OFFS2 ; offset to cell 2: + 4
- INC 4
- STORE FF_OFFS3 ; offset to cell 3: + 4
- LOAD FF_ROW_OFFS
- SHL 1 ; offset to cell 4: row offset * 2
- STORE FF_OFFS4
-
- ; start at column 1
- LOAD FF_CELL_PTR
- INC 4
- STORE FF_CELL_PTR
-FF_ROW:
- LOADC FIREWIDTH-1
- STORE FF_COL_COUNT
-
-FF_COL:
- LOAD FF_CELL_PTR
- LOAD FF_OFFS1
- ADD
- LOADI
-
- LOAD FF_CELL_PTR
- LOAD FF_OFFS2
- ADD
- LOADI
-
- LOAD FF_CELL_PTR
- LOAD FF_OFFS3
- ADD
- LOADI
-
- LOAD FF_CELL_PTR
- LOAD FF_OFFS4
- ADD
- LOADI
-
- ADD
- ADD
- ADD
-
- SHR
- SHR
-
- ; if new cell value > 0, subtract 1 to cool down
- DUP
- CBRANCH.Z FF_SKIP
- DEC 1
-FF_SKIP:
- LOAD FF_CELL_PTR ; load cell ptr
- SWAP ; swap with new value
- STOREI 4 ; store with postincrement
- STORE FF_CELL_PTR ; save new ptr value
-
- LOAD FF_COL_COUNT ; decrement column count
- DEC 1
- DUP
- STORE FF_COL_COUNT
- CBRANCH.NZ FF_COL ; loop if col count <> 0
-
- ; at the end of a row, go to next row
- ; by adding 8 to the cell pointer,
- ; skipping the first cell of the next row
- LOAD FF_CELL_PTR
- INC 8
- STORE FF_CELL_PTR
-
- LOAD FF_ROW_COUNT ; decrement row count
- DEC 1
- DUP
- STORE FF_ROW_COUNT
- CBRANCH.NZ FF_ROW ; loop if row count <> 0
-
-FF_EXIT:
- FPADJ FF_FS
- RET
-
-; framebuffer controller registers
- .EQU FB_RA $900
- .EQU FB_WA $904
- .EQU FB_IO $908
- .EQU FB_PS $90C
- .EQU FB_PD $910
- .EQU FB_CTL $914
- .EQU WORDS_PER_LINE 80
-
-; fire width in vmem words (strict left-to-right evaluation)
- .EQU FFD_ROW_WORDS 1 + FIREWIDTH / 8
-
-; draw all fire cells
-; args: pointer to fire cell buffer, screen x, screen y
- .EQU FFD_CELL_PTR 0
- .EQU FFD_X 4
- .EQU FFD_Y 8
- .EQU FFD_ROW_COUNT 12
- .EQU FFD_ROW_WORDCOUNT 16
- .EQU FFD_VMEM_PTR 20
- .EQU FFD_FS 24
-FASTFIREDRAW:
- FPADJ -FFD_FS
- STORE FFD_Y
- STORE FFD_X
- STORE FFD_CELL_PTR
-
- ; calculate video memory addr
- ; addr = y * 80 + X / 8
- LOAD FFD_Y
- SHL 2 ; y * 16
- SHL 2
- DUP
- SHL 2 ; + y * 64
- ADD ; = y * 80
-
- LOAD FFD_X
- SHR
- SHR
- SHR
- ADD ; + x / 8
-
- DUP
- STORE FFD_VMEM_PTR
- LOADC FB_WA ; set vmem write address
- SWAP
- STOREI
- DROP
-
- LOADC FIREHEIGHT + 1
- STORE FFD_ROW_COUNT
-FFD_ROW:
- LOADC FFD_ROW_WORDS
- STORE FFD_ROW_WORDCOUNT
-
- LOADC FB_WA ; set vmem write address
- LOAD FFD_VMEM_PTR
- STOREI
- DROP
-
-FFD_WORD:
- LOAD FFD_CELL_PTR ; load cell ptr
- LOADC 0 ; vmem word, start with 0
-
- ; leftmost pixel (0)
- OVER ; [ cptr, vmemw, cptr ]
- LOADI ; load cell value [ cptr, vmemw, cellval ]
- SHR ; scale it down (from 7 bits to 4)
- SHR
- SHR ; [ cptr, vmemw, cellval shr 3 ]
- OR ; [ cptr, vmemw ]
- SWAP ; [ vmemw, cptr ]
- INC 4 ; increment cell ptr on stack [ vmemw, cptr + 4 ]
- SWAP ; [ cptr + 4, vmemw ]
-
- SHL 2 ; move bits to left for next pixel
- SHL 2
-
- ; pixel 1
- OVER
- LOADI ; load cell value
- SHR ; scale it down (from 7 bits to 4)
- SHR
- SHR
- OR
- SWAP
- INC 4 ; increment cell ptr on stack
- SWAP
-
- SHL 2 ; move bits to left for next pixel
- SHL 2
-
- ; pixel 2
- OVER
- LOADI ; load cell value
- SHR ; scale it down (from 7 bits to 4)
- SHR
- SHR
- OR
- SWAP
- INC 4 ; increment cell ptr on stack
- SWAP
-
- SHL 2 ; move bits to left for next pixel
- SHL 2
-
- ; pixel 3
- OVER
- LOADI ; load cell value
- SHR ; scale it down (from 7 bits to 4)
- SHR
- SHR
- OR
- SWAP
- INC 4 ; increment cell ptr on stack
- SWAP
-
- SHL 2 ; move bits to left for next pixel
- SHL 2
-
- ; pixel 4
- OVER
- LOADI ; load cell value
- SHR ; scale it down (from 7 bits to 4)
- SHR
- SHR
- OR
- SWAP
- INC 4 ; increment cell ptr on stack
- SWAP
-
- SHL 2 ; move bits to left for next pixel
- SHL 2
-
- ; pixel 5
- OVER
- LOADI ; load cell value
- SHR ; scale it down (from 7 bits to 4)
- SHR
- SHR
- OR
- SWAP
- INC 4 ; increment cell ptr on stack
- SWAP
-
- SHL 2 ; move bits to left for next pixel
- SHL 2
-
- ; pixel 6
- OVER
- LOADI ; load cell value
- SHR ; scale it down (from 7 bits to 4)
- SHR
- SHR
- OR
- SWAP
- INC 4 ; increment cell ptr on stack
- SWAP
-
- SHL 2 ; move bits to left for next pixel
- SHL 2
-
- ; pixel 7
- OVER
- LOADI ; load cell value
- SHR ; scale it down (from 7 bits to 4)
- SHR
- SHR
- OR
- SWAP
- INC 4 ; increment cell ptr on stack
- SWAP
-
- ; store word to vmem
- ; vmem write addr will autoincrement
- LOADC FB_IO
- SWAP
- STOREI
- DROP
-
- STORE FFD_CELL_PTR
-
- ; prepare for next word
- LOAD FFD_ROW_WORDCOUNT
- DEC 1
- DUP
- STORE FFD_ROW_WORDCOUNT
- CBRANCH.NZ FFD_WORD
-
- ; prepare for next row
- LOAD FFD_VMEM_PTR
- LOADC WORDS_PER_LINE
- ADD
- STORE FFD_VMEM_PTR
-
- LOAD FFD_ROW_COUNT
- DEC 1
- DUP
- STORE FFD_ROW_COUNT
- CBRANCH.NZ FFD_ROW
-FFD_EXIT:
- FPADJ FFD_FS
- RET
diff --git a/examples/fire.pas b/examples/fire.pas
deleted file mode 100644
index 22f0217..0000000
--- a/examples/fire.pas
+++ /dev/null
@@ -1,76 +0,0 @@
-{$H1}
-{$S2}
-program fire;
-const MAXX = 30;
- MAXY = 50;
-var firebuf: array [0..MAXY, 0..MAXX] of integer;
-
- firepalette: array [0..15] of integer =
- ( $FFA, $FF8, $FF4, $FF0, $FE0, $FD0, $FA0, $F90,
- $F00, $E00, $D00, $A00, $800, $600, $300, $000);
- x,y:integer;
-
-procedure createPalette;
-var i:integer;
-begin
- for i := 15 downto 0 do
- setpalette(15 - i, firepalette[i]);
-end;
-
-procedure fireItUp;
-var x,y:integer;
-begin
- y := MAXY - 1;
- for x := 1 to MAXX - 1 do
- firebuf[y, x] := random and 127;
-end;
-
-procedure updateFire;
-var i,x,y:integer;
-begin
- for y := 0 to MAXY - 2 do
- for x := 1 to MAXX - 1 do
- begin
- i :=
- ((firebuf[y + 1, x - 1]
- + firebuf[y + 1, x]
- + firebuf[y + 1, x + 1]
- + firebuf[y + 2, x])
- ) shr 2;
- if i > 0 then
- i := i - 1;
- firebuf[y, x] := i;
- end;
-end;
-
-procedure drawFire;
-var x, y, col:integer;
-begin
- for y := 0 to MAXY - 1 do
- begin
- x := 0;
- for col in firebuf[y] do
- begin
- putpixel(300 + x, 150 + y, col shr 3);
- x := x + 1;
- end;
- end;
-end;
-
-begin
- randomize;
- initgraphics;
- createPalette;
- while not conavail do
- begin
- fireItUp;
- updateFire;
- drawFire;
- end;
-
- for y := 0 to MAXY do
- begin
- x := firebuf[y, 10];
- drawline(0, y, x, y, 1);
- end;
-end.
diff --git a/examples/fire2.pas b/examples/fire2.pas
deleted file mode 100644
index 72fb254..0000000
--- a/examples/fire2.pas
+++ /dev/null
@@ -1,84 +0,0 @@
-{$H1}
-{$S1}
-program fire2;
-uses fastfire;
-
-const MAXX = FIREWIDTH;
- MAXY = FIREHEIGHT;
-
-var firecells: FireBuf;
-
- firepalette: array [0..15] of integer =
- { ( $FFA, $FF8, $FF4, $FF0, $FE0, $FD0, $FA0, $F90,
- $F00, $E00, $D00, $A00, $800, $600, $300, $000); }
- ( $FFA, $FFA, $FFA, $FFA, $FF0, $FF0, $FF0, $FF0,
- $FF0, $FD0, $FA0, $C00, $A00, $700, $400, $000);
- x,y:integer;
-
-procedure createPalette;
-var i:integer;
-begin
- for i := 15 downto 0 do
- setpalette(15 - i, firepalette[i]);
-end;
-
-procedure fireItUp;
-var x,y:integer;
-begin
- y := MAXY - 1;
- for x := 1 to MAXX - 1 do
- firecells[y, x] := random and 127;
-end;
-
-
-procedure updateFire;
-var i,x,y:integer;
-begin
- for y := 0 to MAXY - 2 do
- for x := 1 to MAXX - 1 do
- begin
- i :=
- ((firecells[y + 1, x - 1]
- + firecells[y + 1, x]
- + firecells[y + 1, x + 1]
- + firecells[y + 2, x])
- ) shr 2;
- if i > 0 then
- i := i - 1;
- firecells[y, x] := i;
- end;
-end;
-
-procedure drawFire;
-var x, y, col:integer;
-begin
- for y := 0 to MAXY - 1 do
- begin
- x := 0;
- for col in firecells[y] do
- begin
- putpixel(100 + x, 150 + y, col shr 3);
- x := x + 1;
- end;
- end;
-end;
-
-begin
- randomize;
- initgraphics;
- createPalette;
- while not conavail do
- begin
- fireItUp;
- FastFireUpdate(firecells);
- { updateFire; }
- FastFireDraw(firecells, 160, 100);
- { drawFire; }
- end;
-
- for y := 0 to MAXY do
- begin
- x := firecells[y, 10];
- drawline(0, y, x, y, 1);
- end;
-end.
diff --git a/examples/graphbench.pas b/examples/graphbench.pas
deleted file mode 100644
index 9abbfba..0000000
--- a/examples/graphbench.pas
+++ /dev/null
@@ -1,125 +0,0 @@
-program graphbench;
-uses sprites;
-
-var starttime,endtime:DateTime;
- spriteData:SpritePixels;
-
-procedure readSpriteData(filename:string);
-var f:file;
-begin
- open(f,filename,ModeReadOnly);
- seek(f,8); (* skip file header *)
- read(f,spriteData);
- close(f);
-end;
-
-procedure startBench(name:string);
-begin
- write(name:20, ' ');
- starttime := GetTime;
-end;
-
-procedure endBench;
-var secDelta, minDelta, hourDelta:integer;
- procedure write2Digits(i:integer);
- begin
- if i < 10 then
- write('0');
- write(i);
- end;
-begin
- endTime := GetTime;
-
- hourDelta := endtime.hours - starttime.hours;
- minDelta := endtime.minutes - starttime.minutes;
- secDelta := endtime.seconds - starttime.seconds;
-
- if secDelta < 0 then
- begin
- secDelta := 60 + secDelta;
- minDelta := minDelta - 1;
- end;
-
- if minDelta < 0 then
- begin
- minDelta := 60 + minDelta;
- hourDelta := hourDelta - 1;
- end;
-
- write2Digits(hourDelta);
- write(':'); write2Digits(minDelta);
- write(':'); write2Digits(secDelta);
- writeln;
-end;
-
-function randint(lessthan:integer):integer;
-var r:integer;
-begin
- r := random and 511;
- if r >= lessthan then
- r := r - lessthan;
- randint := r;
-end;
-
-procedure drawsprites(count:integer);
-var i,col,x,y:integer;
-begin
- col := 1;
- for i := 1 to count do
- begin
- x := randint(350);
- y := randint(350);
- PutSprite(x,y,spriteData);
- col := col + 1;
- if col > 15 then col := 1;
- end;
-end;
-
-procedure drawlines(count:integer);
-var i,col,x1,y1,x2,y2:integer;
-begin
- col := 1;
- for i := 1 to count do
- begin
- x1 := randint(500);
- y1 := randint(400);
- x2 := randint(500);
- y2 := randint(400);
- DrawLine(x1,y1,x2,y2,col);
- col := col + 1;
- if col > 15 then col := 1;
- end;
-end;
-
-procedure drawpoints(count:integer);
-var i,col,x,y:integer;
-begin
- col := 1;
- for i := 1 to count do
- begin
- x := randint(500);
- y := randint(400);
- PutPixel(x,y,col);
- col := col + 1;
- if col > 15 then col := 1;
- end;
-end;
-
-begin
- readSpriteData('rocket.sprt');
-
- InitGraphics;
- startBench('points 200K');
- drawpoints(200000);
- endBench;
-
- InitGraphics;
- startBench('lines 10K');
- drawlines(10000);
- endBench;
-
- InitGraphics;
- startBench('sprites 50K');
- drawsprites(50000);
- endBench;
-end.
diff --git a/examples/pcmtest.pas b/examples/pcmtest.pas
deleted file mode 100644
index 5122219..0000000
--- a/examples/pcmtest.pas
+++ /dev/null
@@ -1,56 +0,0 @@
-{$H2560}
-program pcmtest2;
-uses pcmaudio;
-
-var filename:string;
- buf:SndBufPtr;
- sampleRate:integer;
- err:integer;
- done:boolean;
- c:char;
-
-function readAudioFile(fname:string):SndBufPtr;
-var i,size:integer;
- c:char;
- buf:SndBufPtr;
- f:file;
-begin
- open(f, fname, 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);
-
- readAudioFile := buf;
-end;
-
-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 := 22050;
-
- buf := readAudioFile(filename);
-
- PlaySample(buf, sampleRate);
-
- dispose(buf);
-end.
diff --git a/examples/pcmtest2.pas b/examples/pcmtest2.pas
deleted file mode 100644
index b5bf47a..0000000
--- a/examples/pcmtest2.pas
+++ /dev/null
@@ -1,74 +0,0 @@
-{$H2560}
-program pcmtest2;
-uses pcmaudio;
-
-var filename:string;
- buf:SndBufPtr;
- sampleRate:integer;
- err:integer;
- done:boolean;
- c:char;
-
-function readAudioFile(fname:string):SndBufPtr;
-var i,size:integer;
- c:char;
- buf:SndBufPtr;
- f:file;
-begin
- open(f, fname, 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);
-
- readAudioFile := buf;
-end;
-
-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 := 32000;
-
- buf := readAudioFile(filename);
-
- SampleQStart(buf, false, sampleRate);
-
- write('Press ESC to stop> ');
- done := false;
- while not done do
- begin
- read(c);
- if c = #27 then
- begin
- done := true; writeln(';');
- end
- else
- if c = '?' then
- begin
- writeln; writeln('Queue: ', SampleQSize);
- end;
- end;
-
- SampleQStop;
-
- dispose(buf);
-end.
diff --git a/examples/sprites.s b/examples/sprites.s
index 5f50081..3391339 100644
--- a/examples/sprites.s
+++ b/examples/sprites.s
@@ -3,16 +3,31 @@
.EQU WORDS_PER_LINE 80
.EQU FB_RA $900
- .EQU FB_WA $904
- .EQU FB_IO $908
- .EQU FB_PS $90C
- .EQU FB_PD $910
- .EQU FB_CTL $914
- .EQU FB_SHIFTER $918
- .EQU FB_SHIFTCOUNT $91C
- .EQU FB_SHIFTERM $920
- .EQU FB_SHIFTERSP $924
- .EQU FB_MASKGEN $928
+ .EQU FB_WA $901
+ .EQU FB_IO $902
+ .EQU FB_PS $903
+
+; calculate mask for a word of pixels
+; args: word of pixels with four bits per pixel
+; returns: value that masks out all pixels that are set
+CALC_MASK:
+ LOADC $F ; pixel mask
+C_M_L0:
+ SWAP ; swap mask and pixels value
+ AND.S1.X2Y ; isolate one pixel, keep args
+ CBRANCH.Z C_M_L1 ; if pixel is zero, dont set mask bits
+ OVER ; copy current mask
+ OR ; or into pixels value
+C_M_L1:
+ SWAP ; swap back, ToS is now mask bits
+ SHL 2 ; shift mask for next pixel to the left
+ SHL 2
+
+ DUP
+ CBRANCH.NZ C_M_L0 ; if mask is zero, we are done
+ DROP ; remove mask bits
+ NOT ; invert result
+ RET
; calculate vmem address from coordinates
; args: x,y
@@ -52,19 +67,13 @@ CALC_VMEM_ADDR:
.EQU PS_SHIFT_C 20
.EQU PS_SPILL 24
.EQU PS_STRIPE_C 28
- .EQU PS_BPSAVE 32
- .EQU PS_FS 36
+ .EQU PS_FS 32
PUTSPRITE:
FPADJ -PS_FS
STORE PS_SPRITE_DATA
STORE PS_Y
STORE PS_X
- LOADREG BP
- STORE PS_BPSAVE
- LOADC 0
- STOREREG BP
-
; calculate vmem address
LOAD PS_X
LOAD PS_Y
@@ -72,6 +81,11 @@ PUTSPRITE:
CALL
STORE PS_VMEM_ADDR
+ LOAD PS_X ; shift count = x mod 8
+ LOADC 7
+ AND
+ STORE PS_SHIFT_C
+
LOADC SPRITE_HEIGHT
STORE PS_SPRITE_LINES
@@ -79,10 +93,12 @@ PUTSPRITE:
PS_LOOP1:
; set read and write address
; in the vga controller
+ LOADC FB_RA ; read address register
LOAD PS_VMEM_ADDR
- DUP
- STORE.B FB_RA
- STORE.B FB_WA
+ STOREI 1 ; use autoincrement to get to the next register
+ LOAD PS_VMEM_ADDR
+ STOREI
+ DROP
LOAD PS_SPRITE_DATA ; address of sprite data
DUP
@@ -90,20 +106,61 @@ PS_LOOP1:
STORE PS_SPRITE_DATA ; and store it again
LOADI ; load word from orig. address
- ; ------- one word of sprite pixels on stack
- STORE.B FB_SHIFTER
- LOAD PS_X
- STORE.B FB_SHIFTCOUNT
+ LOADC 0
+ STORE PS_SPILL
- LOAD.B FB_SHIFTERM ; get shifted mask
- NOT
- LOAD.B FB_IO ; and background pixel data
- AND ; remove foreground pixels
+ ; loop to shift pixel data to right
+ LOAD PS_SHIFT_C ; load shift count
+PS_LOOP2:
+ DUP ; test it for zero
+ CBRANCH.Z PS_LOOP2_X
- LOAD.B FB_SHIFTER ; get shifted pixels
- OR ; combine with background
- STORE.B FB_IO ; store into vmem
+ SWAP ; swap count with pixels
+
+ ; save the pixel that is shifted out
+ LOADC $F ; mask the four bits
+ AND.S0 ; keep original value on stack
+ BROT ; and move them to MSB
+ BROT
+ BROT
+ SHL 2
+ SHL 2 ; shift by 28 in total
+
+ LOAD PS_SPILL ; load spill bits
+ SHR ; shift by four to make space
+ SHR
+ SHR
+ SHR
+ OR ; or with orig value
+ STORE PS_SPILL ; store new value
+
+ SHR ; shift pixels right
+ SHR ; four bits per pixel
+ SHR
+ SHR
+
+ SWAP ; swap back, count now ToS
+ DEC 1
+ BRANCH PS_LOOP2
+PS_LOOP2_X:
+ DROP ; remove shift count, shifted pixels now in ToS
+
+ DUP
+ LOADCP CALC_MASK ; calculate sprite mask for this word
+ CALL
+
+ LOADCP FB_IO ; address of the i/o register
+ LOADI ; read word from video mem
+
+ AND ; and word with mask
+
+ OR ; OR sprite data with original pixels
+
+ LOADCP FB_IO
+ SWAP
+ STOREI ; store result into i/o reg
+ DROP
; set counter for remaining stripes
LOADC SPRITE_STRIPES - 1
@@ -113,8 +170,8 @@ PS_LOOP1:
; process spilled bits and next vertical stripe of sprite data
;
PS_NEXT_STRIPE:
- ;use spill bits from first column
- LOAD.B FB_SHIFTERSP
+ ; put spill bits on stack for later
+ LOAD PS_SPILL
LOAD PS_SPRITE_DATA ; address of sprite data
DUP
@@ -122,21 +179,65 @@ PS_NEXT_STRIPE:
STORE PS_SPRITE_DATA ; and store it again
LOADI ; load word from orig. address
- STORE.B FB_SHIFTER ; store into shifter
- LOAD PS_X
- STORE.B FB_SHIFTCOUNT ; shift stuff
- LOAD.B FB_SHIFTER ; get shifted pixels
- OR ; combine with spill bits (see above)
+ ; reset spill bits
+ LOADC 0
+ STORE PS_SPILL
+
+ ; last spill bits are on ToS now
+
+ ; shift pixel data to right
+ LOAD PS_SHIFT_C ; load shift count
+PS_LOOP3: ; test it for zero
DUP
- STORE.B FB_MASKGEN ; store to mask reg to get new mask
+ CBRANCH.Z PS_LOOP3_X
- LOAD.B FB_MASKGEN ; get mask for spill bits + shifted pixels
- NOT
- LOAD.B FB_IO ; get vmem data
- AND ; remove foreground pixels from bg
+ SWAP ; swap count with pixels
- OR ; combine with shifted pixels
- STORE.B FB_IO ; write to vmem
+ ; save the pixel that is shifted out
+ LOADC $F ; mask the four bits
+ AND.S0 ; keep original value on stack
+ BROT ; and move them to MSB
+ BROT
+ BROT
+ SHL 2
+ SHL 2 ; shift by 28 in total
+
+ LOAD PS_SPILL ; load spill bits
+ SHR ; shift by four to make space
+ SHR
+ SHR
+ SHR
+ OR ; or with orig value
+ STORE PS_SPILL ; store new value
+
+ SHR ; shift pixels right
+ SHR ; four bits per pixel
+ SHR
+ SHR
+
+ SWAP ; swap back, count now ToS
+ DEC 1
+ BRANCH PS_LOOP3
+PS_LOOP3_X:
+ DROP ; remove shift count, shifted pixels now in ToS
+
+ OR ; or together with spill bits
+
+ DUP
+ LOADCP CALC_MASK ; calculate sprite mask
+ CALL
+
+ LOADCP FB_IO ; load original pixels
+ LOADI
+
+ AND ; and with mask
+
+ OR ; or together with original pixels
+
+ LOADCP FB_IO
+ SWAP
+ STOREI
+ DROP
LOAD PS_STRIPE_C ; decrement stripe count
DEC 1
@@ -145,19 +246,22 @@ PS_NEXT_STRIPE:
CBRANCH.NZ PS_NEXT_STRIPE ; if non-zero, next stripe
; write spilled bits of the last stripe into next vmem word
- LOAD.B FB_SHIFTERSP ; get spill bits
+ LOAD PS_SPILL ; get spill bits
DUP
- STORE.B FB_MASKGEN
- LOAD.B FB_MASKGEN ; get sprite mask for spill bits
- NOT
+ LOADCP CALC_MASK ; calculate sprite mask for spill bits
+ CALL
- LOAD.B FB_IO ; load next vmem word
+ LOADCP FB_IO
+ LOADI ; load next vmem word
AND ; apply sprite mask
OR ; OR in spill bits
- STORE.B FB_IO ; write to vmem
-
+ LOADCP FB_IO
+ SWAP ; swap pixels and addr
+ STOREI ; write back
+ DROP
+
LOAD PS_SPRITE_LINES ; decrement lines count
DEC 1
DUP
@@ -171,10 +275,7 @@ PS_NEXT_STRIPE:
BRANCH PS_LOOP1
PS_L_XT:
DROP
-
- LOAD PS_BPSAVE
- STOREREG BP
-
+
FPADJ PS_FS
RET
@@ -221,7 +322,7 @@ UD_S_L1:
; store vmem offset into write addr reg
LOADCP FB_WA
LOAD UD_S_OFFSET
- STOREI 4 ; ugly but fast: reuse addr
+ STOREI 1 ; ugly but fast: reuse addr
; with postincrement to
; get to FB_IO for STOREI below
diff --git a/examples/xmas25.pas b/examples/xmas25.pas
deleted file mode 100644
index 1a7d8b5..0000000
--- a/examples/xmas25.pas
+++ /dev/null
@@ -1,251 +0,0 @@
-{$H2560}
-{$S8}
-program xmas252;
-uses pcmaudio, fastfire, tiles;
-
-const MAXX = FIREWIDTH;
- MAXY = FIREHEIGHT;
-
-(* type PixelData = array[0..31999] of integer; *)
-
-type Picture = record
- magic:integer;
- mode:integer;
- palette: array[0..15] of integer;
- pixels: PixelData;
- end;
-
-var firecells: FireBuf;
-
- firepalette: array [0..15] of integer =
- { ( $FFA, $FF8, $FF4, $FF0, $FE0, $FD0, $FA0, $F90,
- $F00, $E00, $D00, $A00, $800, $600, $300, $000); }
- { ( $FFA, $FFA, $FFA, $FFA, $FF0, $FF0, $FF0, $FF0, }
- ( $00F, $00F, $00F, $00F, $00F, $00F, $00F, $00F,
- $FF0, $FD0, $FA0, $C00, $A00, $700, $400, $000);
- x,y:integer;
- infile:file;
- pic:^Picture;
- tilesheet:^Picture;
- animationTick:integer;
- animationHold:integer;
- animationState:integer;
-
- filename: string;
-
- audiodata: SndBufPtr;
-
-procedure createPalette;
-var i:integer;
-begin
- for i := 15 downto 0 do
- setpalette(15 - i, firepalette[i]);
-end;
-
-procedure fireItUp;
-var x,y:integer;
-begin
- y := MAXY - 1;
- for x := 1 to MAXX - 1 do
- firecells[y, x] := random and 127;
-end;
-
-
-procedure updateFire;
-var i,x,y:integer;
-begin
- for y := 0 to MAXY - 2 do
- for x := 1 to MAXX - 1 do
- begin
- i :=
- ((firecells[y + 1, x - 1]
- + firecells[y + 1, x]
- + firecells[y + 1, x + 1]
- + firecells[y + 2, x])
- ) shr 2;
- if i > 0 then
- i := i - 1;
- firecells[y, x] := i;
- end;
-end;
-
-procedure drawFire(startX,startY:integer);
-var x, y, col, col2:integer;
-begin
- for y := 0 to MAXY - 1 do
- begin
- x := 0;
- for col in firecells[y] do
- begin
- { scale and clamp color value }
- col2 := col shr 3;
- if col2 > FIREMAXCOLOR then col2 := FIREMAXCOLOR;
-
- putpixel(startX + x, startY + y, col2);
- x := x + 1;
- end;
- end;
-end;
-
-procedure readBackgroundPic(filename:string);
-var i:integer;
-begin
- open(infile, filename, ModeReadonly);
- read(infile, pic^);
- close(infile);
-
- for i := 0 to 15 do
- SetPalette(i, pic^.palette[i]);
-
- PutScreen(pic^.pixels);
-end;
-
-procedure animate;
-var tileSrcX,tilesrcY:integer;
-begin
- animationTick := animationTick + 1;
-
- if animationHold = 0 then
- animationHold := 40;
-
- if animationTick < animationHold then
- exit;
-
- animationTick := 0;
-
- case animationState of
- 0: begin
- tileSrcX := 0;
- tileSrcY := 0;
- animationHold := 40;
- end;
- 1: begin
- tileSrcX := 19;
- tileSrcY := 0;
- animationHold := 20;
-
- if random and 7 > 4 then
- animationState := -1;
- end;
- 2: begin
- tileSrcX := 38;
- tileSrcY := 0;
- animationHold := 2;
- end;
- 3: begin;
- tileSrcX := 57;
- tileSrcY := 0;
- animationHold := 2;
- end;
- 4: begin
- tileSrcX := 0;
- tileSrcY := 13;
- animationHold := 15;
- end;
- 5: begin
- tileSrcX := 57;
- tileSrcY := 0;
- animationHold := 2;
- end;
- 6: begin
- tileSrcX := 38;
- tileSrcY := 0;
- animationHold := 2;
- end;
- 7: begin
- tileSrcX := 0;
- tileSrcY := 0;
- animationHold := 2;
- animationState := -1;
- end;
- end;
-
- CopyTilesScr(tilesheet^.pixels,
- tileSrcX, tileSrcY,
- 34,34,
- 19,13);
-
- animationState := animationState + 1;
-end;
-
-
-procedure readTilesheet;
-var filename:string;
- i:integer;
-begin
- filename := 'tilesheet.pict';
- open(infile, filename, ModeReadonly);
- read(infile, tilesheet^);
- close(infile);
-end;
-
-function newAudioData(fname:string):SndBufPtr;
-var i,size:integer;
- c:char;
- buf:SndBufPtr;
- f:file;
-begin
- open(f, fname, 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);
-
- newAudioData := buf;
-end;
-
-
-begin
- if ParamCount > 0 then
- filename := ParamStr(1)
- else
- filename := 'xmas25bg.pict';
-
- Randomize;
-
- audiodata := newAudioData('fireplace-loop.tdrau');
-
- InitGraphics;
-
- new(pic);
- readBackgroundPic(filename);
-
- new(tilesheet);
- readTilesheet;
-
- SampleQStart(audiodata, true, 22050);
-
- while not ConAvail do
- begin
- fireItUp;
- FastFireUpdate(firecells);
- { updateFire; }
- FastFireDraw(firecells, 216, 165);
- { drawFire(216, 165); }
- animate;
- end;
-
- SampleQStop;
-
- for y := 0 to MAXY do
- begin
- x := firecells[y, 10];
- drawline(0, y, x, y, 1);
-
- end;
-
- InitGraphics;
-
- dispose(tilesheet);
- dispose(pic);
- dispose(audiodata);
-end.
diff --git a/lib/corelib.s b/lib/corelib.s
index 1ac12e9..8b8f403 100644
--- a/lib/corelib.s
+++ b/lib/corelib.s
@@ -701,37 +701,113 @@ CMPWORDS_XT2:
; --------- Graphics Library ---------------
; vga controller registers
.EQU FB_RA $900
- .EQU FB_WA $904
- .EQU FB_IO $908
- .EQU FB_PS $90C
- .EQU FB_PD $910
- .EQU FB_CTL $914
- .EQU FB_SHIFTER $918
- .EQU FB_SHIFTCOUNT $91C
- .EQU FB_SHIFTERM $920
- .EQU FB_SHIFTERSP $924
- .EQU FB_MASKGEN $928
+ .EQU FB_WA $901
+ .EQU FB_IO $902
+ .EQU FB_PS $903
+ .EQU FB_PD $904
+ .EQU FB_CTL $905
+; set a pixel in fb memory
+; parameters: x,y - coordinates
+PUTPIXEL_1BPP:
+ ; calculate vmem address:
+ OVER ; duplicate x
+ ; divide x by 32
+ SHR
+ SHR
+ SHR
+ SHR
+ SHR
+ SWAP
+ ; multiply y by words per line
+ SHL 2
+ SHL 2
+ SHL
-; draw a single pixel
-; args: x, y, color
+ ADD ; add results together for vmem addr
+ DUP
+ LOADCP FB_WA
+ SWAP
+ STOREI ; store to framebuffer write addr register
+ DROP
+ LOADCP FB_RA ; and to framebuffer read addr register
+ SWAP
+ STOREI
+ DROP
+
+ ; x is now at top of stack
+ ; get bit value from x modulo 32
+ LOADC 31
+ AND
+ SHL 2 ; (x & 31) * 4 = offset into table
+ LOADCP INT_TO_PIX_TABLE
+ ADD
+ LOADI
+
+ LOADCP FB_IO
+ ; read old vmem value
+ LOADCP FB_IO
+ LOADI
+ ; or in new bit
+ OR
+ ; write new value
+ STOREI
+ DROP
+
+ RET
+
+INT_TO_PIX_TABLE:
+ .WORD %10000000_00000000_00000000_00000000
+ .WORD %01000000_00000000_00000000_00000000
+ .WORD %00100000_00000000_00000000_00000000
+ .WORD %00010000_00000000_00000000_00000000
+ .WORD %00001000_00000000_00000000_00000000
+ .WORD %00000100_00000000_00000000_00000000
+ .WORD %00000010_00000000_00000000_00000000
+ .WORD %00000001_00000000_00000000_00000000
+ .WORD %00000000_10000000_00000000_00000000
+ .WORD %00000000_01000000_00000000_00000000
+ .WORD %00000000_00100000_00000000_00000000
+ .WORD %00000000_00010000_00000000_00000000
+ .WORD %00000000_00001000_00000000_00000000
+ .WORD %00000000_00000100_00000000_00000000
+ .WORD %00000000_00000010_00000000_00000000
+ .WORD %00000000_00000001_00000000_00000000
+ .WORD %00000000_00000000_10000000_00000000
+ .WORD %00000000_00000000_01000000_00000000
+ .WORD %00000000_00000000_00100000_00000000
+ .WORD %00000000_00000000_00010000_00000000
+ .WORD %00000000_00000000_00001000_00000000
+ .WORD %00000000_00000000_00000100_00000000
+ .WORD %00000000_00000000_00000010_00000000
+ .WORD %00000000_00000000_00000001_00000000
+ .WORD %00000000_00000000_00000000_10000000
+ .WORD %00000000_00000000_00000000_01000000
+ .WORD %00000000_00000000_00000000_00100000
+ .WORD %00000000_00000000_00000000_00010000
+ .WORD %00000000_00000000_00000000_00001000
+ .WORD %00000000_00000000_00000000_00000100
+ .WORD %00000000_00000000_00000000_00000010
+ .WORD %00000000_00000000_00000000_00000001
+
+PUTMPIXEL:
+ LOADC 1
+; set a pixel in fb memory
+; parameters: x,y,color - coordinates, color value (0-15)
PUTPIXEL:
PUTPIXEL_4BPP:
.EQU PUTPIXEL_X 0
.EQU PUTPIXEL_Y 4
.EQU PUTPIXEL_COLOR 8
- .EQU PUTPIXEL_BPSAV 12
+ .EQU PUTPIXEL_PIXPOS 12
.EQU PUTPIXEL_FS 16
FPADJ -PUTPIXEL_FS
+
STORE PUTPIXEL_COLOR
STORE PUTPIXEL_Y
STORE PUTPIXEL_X
- LOADREG BP
- STORE PUTPIXEL_BPSAV
- LOADC 0
- STOREREG BP
; calculate vmem address: (x / 8) + (y * 80)
LOAD PUTPIXEL_X
@@ -746,60 +822,86 @@ PUTPIXEL_4BPP:
SHL 2 ; * 16
DUP
SHL 2; * 64
- ADD ; y*16 + y*64
+ ADD ; x*16 + x*64
ADD ; add results together for vmem addr
- DUP
- STORE.B FB_WA ; set as write and read addresses
- STORE.B FB_RA
+ LOADCP FB_WA
+ OVER
+ STOREI ; store to framebuffer write addr register
+ DROP
+ LOADCP FB_RA ; and to framebuffer read addr register
+ SWAP ; swap addr and value for STOREI
+ STOREI
+ DROP
+
+ LOAD PUTPIXEL_X
+ ; |0000.0000|0000.0000|0000.0000|0000.1111|
+ LOADC 7
+ AND ; calculate pixel position in word
+ LOADC 7
+ SWAP
+ SUB ; pixpos = 7 - (x & 7)
+ STORE PUTPIXEL_PIXPOS
LOAD PUTPIXEL_COLOR
- CBRANCH.Z PUTPX_CLR ; color 0 is special case
-
- ; create pixel data from color value in
- ; leftmost pixel data bits (31-28)
- LOADC 0
- LOAD PUTPIXEL_COLOR
- BPLC
+ LOAD PUTPIXEL_PIXPOS
+ SHR ; rcount = pixpos / 2
+ROTLOOP_:
+ DUP ; exit loop if rcount is 0
+ CBRANCH.Z ROTLOOP_END
+ SWAP ; pixel value is now on top of stack
+ BROT ; value = value << 8
+ SWAP ; rcount is now on top of stack
+ DEC 1 ; rcount = rcount - 1
+ BRANCH ROTLOOP_
+ROTLOOP_END:
+ DROP ; drop rcount
+ ; shifted pixel value is now at top of stack
+ LOAD PUTPIXEL_PIXPOS
+ LOADC 1
+ AND
+ CBRANCH.Z EVEN_PIXPOS
+ SHL 2 ; if pixpos is odd, shift by 4 bits
SHL 2
- SHL 2
- STORE.B FB_SHIFTER ; store pixel into shifter
+EVEN_PIXPOS:
+ LOAD PUTPIXEL_X
+ ; get bit value from x modulo 8
+ LOADC 7
+ AND
+ SHL 2 ; (x & 7) * 4 = offset into table
+ LOADCP INT_TO_MASK_TABLE
+ ADD
+ LOADI
- LOAD PUTPIXEL_X ; use x coord as shift count
- STORE.B FB_SHIFTCOUNT ; writing triggers shifting
+ ; read old vmem value
+ LOADCP FB_IO
+ LOADI
+ ; mask bits
+ AND
+ ; or in shifted pixel value
+ OR
- LOAD.B FB_SHIFTERM ; get shift result as mask
- NOT ; invert to get background mask
- LOAD.B FB_IO ; get background pixel data
- AND ; remove bits for new pixel from bg
-
- LOAD.B FB_SHIFTER ; load shifted pixel
- OR ; OR in new pixel bits
- STORE.B FB_IO ; write new pixel data word to vmem
-
-PUTPX_XT:
- LOAD PUTPIXEL_BPSAV
- STOREREG BP
+ ; write new value
+ LOADCP FB_IO
+ SWAP
+ STOREI
+ DROP
FPADJ PUTPIXEL_FS
RET
-PUTPX_CLR:
- LOADCP $F0000000 ; mask for leftmost pixel
- STORE.B FB_SHIFTER ; shift accordingly
- LOAD PUTPIXEL_X
- STORE.B FB_SHIFTCOUNT
-
- LOAD.B FB_SHIFTER ; get shifted value
- NOT ; invert for real mask
- LOAD.B FB_IO ; get background pixels
- AND ; clear pixel with mask
- STORE.B FB_IO ; no need to OR in new pixel, just store to vmem
-
- BRANCH PUTPX_XT
-
+ .CPOOL
+INT_TO_MASK_TABLE:
+ .WORD %00001111_11111111_11111111_11111111
+ .WORD %11110000_11111111_11111111_11111111
+ .WORD %11111111_00001111_11111111_11111111
+ .WORD %11111111_11110000_11111111_11111111
+ .WORD %11111111_11111111_00001111_11111111
+ .WORD %11111111_11111111_11110000_11111111
+ .WORD %11111111_11111111_11111111_00001111
+ .WORD %11111111_11111111_11111111_11110000
; draw a line between two points
; parameters: x0, y0, x1, y1, color
diff --git a/lib/pcmaudio.inc b/lib/pcmaudio.inc
deleted file mode 100644
index dc1dbba..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;loop:boolean;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 ebe812a..0000000
--- a/lib/pcmaudio.s
+++ /dev/null
@@ -1,304 +0,0 @@
- .EQU AUDIO_BASE $A00
- .EQU IRQC_REG $980
- .EQU IRQC_EN $80
- .EQU CPU_FREQ 77000000
-
-; args: sample rate
-START_PCMAUDIO:
- ; calculate clock divider
- LOADCP CPU_FREQ
- SWAP
- LOADCP _DIV
- CALL
-
- LOADC AUDIO_BASE + 4
- SWAP ; put clock divider on ToS
- STOREI 4
- LOADCP 32768 ; set amplitude to biased 0
- STOREI
- DROP
-
- LOADC AUDIO_BASE
- LOADC 1 ; enable channel
- 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+8 ; store amplitude value
- SWAP
- STOREI
- DROP
- RET
-
-; set sample queue count and pointer from string header
-; args: pointer to string/SndBufPtr
-_STR2SMPLQPTR:
- 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
- RET
-
-; start interrupt-driven sample playback
-; args: pointer to pascal string, loop flag, sample rate
-SAMPLEQSTART:
- LOADCP START_PCMAUDIO ; sample rate is on ToS as arg to subroutine
- CALL
-
- SWAP ; swap loop flag and buf ptr
-
- LOADCP _STR2SMPLQPTR
- CALL
-
- ; loop flag is now on ToS
- CBRANCH.Z SQ_S_1
- ; if nonzero, set loop ptr
- LOADCP SMPLQ_PTR
- LOADI
- DEC 8 ; subtract offset for string header again
- BRANCH SQ_S_0
-SQ_S_1:
- LOADC 0
-SQ_S_0:
- LOADCP SMPLQ_NEXT
- SWAP
- STOREI
- DROP
-
- LOADC AUDIO_BASE
- LOADC 17 ; enable channel, enable interrupt
- STOREI
- 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_NEXT: .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 which contains two samples
- DUP
-
- BROT ; get high half-word
- BROT
- LOADCP $FFFF
- AND
-
- LOADC AUDIO_BASE+8
- 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
-
- ; put up to 16 samples into the sample queue
- LOADCP SMPLQ_COUNT
- LOADI ; load word counter again
- LOADC 7 ; check if count modulo 7 = 0
- AND
- CBRANCH.NZ SMPLQ_I_L ; if not, next two samples
-
- ; check if fifo is full
- ; does not work reliably when running in DRAM,
- ; maybe because at least one sample has already played
- ; since start of ISR?
-; LOADC AUDIO_BASE
-; LOADI
-; LOADC 8 ; fifo_full
-; AND
-; CBRANCH.Z SMPLQ_I_L ; next sample if not full
-
- BRANCH SMPLQ_I_XT
-
- ; end of sample buffer, check for next
-SMPLQ_I_END:
- DROP
- DROP
-
- LOADCP SMPLQ_NEXT ; skip to end
- LOADI ; if NEXT ptr is zero
- DUP
- CBRANCH.Z SMPLQ_I_END1
-
- LOADCP _STR2SMPLQPTR
- CALL
-
- BRANCH SMPLQ_I_XT
-
- ; end playback, set ptr and counter to zero
-SMPLQ_I_END1:
- DROP
- LOADCP SMPLQ_PTR
- LOADC 0
- STOREI
- DROP
- LOADCP SMPLQ_COUNT
- LOADC 0
- STOREI
- DROP
-
- ; set amplitude out to zero (biased)
- LOADC AUDIO_BASE+8
- LOADCP 32768
- STOREI
- DROP
-
- ; exit without enabling interrupts for this channel
- BRANCH SMPLQ_I_XT2
-
-SMPLQ_I_XT:
- LOADC AUDIO_BASE
- LOADC 17 ; re-enable channel interrupt
- STOREI
- DROP
-
-SMPLQ_I_XT2:
- 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/pcomp/Makefile b/pcomp/Makefile
index 4afc3ef..e183f73 100644
--- a/pcomp/Makefile
+++ b/pcomp/Makefile
@@ -13,7 +13,7 @@ LSYMGEN=./lsymgen
.pas:
fpc -Mobjfpc -gl $<
-all: libs pcomp sasm sdis lsymgen shortgen nativecomp nativeprogs
+all: pcomp sasm sdis lsymgen shortgen nativeprogs
libs: pcomp sasm lsymgen shortgen
$(SASM) ../lib/coreloader.s
@@ -22,9 +22,9 @@ libs: pcomp sasm lsymgen shortgen
$(SASM) ../lib/stdlibwrap.s ../lib/stdlib.lib
$(LSYMGEN) ../lib/stdlibwrap.sym ../lib/stdlib.lsym
-test: libs sasm.s pcomp.s lsymgen.s shortgen.s
+test: sasm.s pcomp.s lsymgen.s shortgen.s
-testprgs: libs sasm.prog pcomp.prog lsymgen.prog shortgen.prog
+testprgs: sasm.prog pcomp.prog lsymgen.prog shortgen.prog
nativecomp: libs pcomp.prog sasm.prog lsymgen.prog shortgen.prog
@@ -41,5 +41,4 @@ examples: nativecomp ../tests/readtest.prog ../tests/readchartest.prog ../tests/
-$(MAKE) -C ../rogue -f Makefile.tridoracpu
clean:
- rm -f pcomp sasm sdis libgen lsymgen shortgen*.o *.s *.prog \
- ../lib/stdlib.s ../lib/stdlib.lib ../lib/stdlib.lsym
+ rm -f pcomp sasm sdis libgen lsymgen *.o *.s *.prog
diff --git a/pcomp/emit.pas b/pcomp/emit.pas
index d440951..a201714 100644
--- a/pcomp/emit.pas
+++ b/pcomp/emit.pas
@@ -324,9 +324,7 @@ begin
rewindStringList(usedUnits);
while nextStringListItem(usedUnits, unitName) do
emitInclude(unitName + UnitSuffix2);
- (* _END label needs to be word-aligned because
- it is used as the start of the heap *)
- emitIns('.ALIGN');
+
emitLabelRaw('_END');
end;
diff --git a/pcomp/sasm.pas b/pcomp/sasm.pas
index d032748..1858f11 100644
--- a/pcomp/sasm.pas
+++ b/pcomp/sasm.pas
@@ -2056,9 +2056,6 @@ begin
operandValue := 0;
emitBlock(count, operandValue);
end
- else
- if lastToken.tokenText = '.ALIGN' then
- alignOutput(wordSize)
else
errorExit2('Unrecognized directive', lastToken.tokenText);
end;
diff --git a/progs/xfer.pas b/progs/xfer.pas
index 0d871d2..13a7cc2 100644
--- a/progs/xfer.pas
+++ b/progs/xfer.pas
@@ -226,7 +226,6 @@ begin
if not invalid then
begin
open(xferFile, filename, ModeOverwrite);
- blockNo := 0;
done := false;
repeat
serReadBlock(ok);
diff --git a/tridoracpu/tridoracpu.srcs/Arty-A7-35-Master.xdc b/tridoracpu/tridoracpu.srcs/Arty-A7-35-Master.xdc
index d2c3160..2a33ae0 100644
--- a/tridoracpu/tridoracpu.srcs/Arty-A7-35-Master.xdc
+++ b/tridoracpu/tridoracpu.srcs/Arty-A7-35-Master.xdc
@@ -8,8 +8,8 @@ set_property -dict {PACKAGE_PIN E3 IOSTANDARD LVCMOS33} [get_ports clk]
create_clock -period 10.000 -name sys_clk_pin -waveform {0.000 5.000} -add [get_ports clk]
## Switches
-#set_property -dict {PACKAGE_PIN A8 IOSTANDARD LVCMOS33} [get_ports sw0]
-#set_property -dict {PACKAGE_PIN C11 IOSTANDARD LVCMOS33} [get_ports sw1]
+set_property -dict {PACKAGE_PIN A8 IOSTANDARD LVCMOS33} [get_ports sw0]
+set_property -dict {PACKAGE_PIN C11 IOSTANDARD LVCMOS33} [get_ports sw1]
#set_property -dict { PACKAGE_PIN C10 IOSTANDARD LVCMOS33 } [get_ports { sw[2] }]; #IO_L13N_T2_MRCC_16 Sch=sw[2]
#set_property -dict { PACKAGE_PIN A10 IOSTANDARD LVCMOS33 } [get_ports { sw[3] }]; #IO_L14P_T2_SRCC_16 Sch=sw[3]
@@ -34,7 +34,7 @@ set_property -dict {PACKAGE_PIN T9 IOSTANDARD LVCMOS33} [get_ports led2]
set_property -dict {PACKAGE_PIN T10 IOSTANDARD LVCMOS33} [get_ports led3]
## Buttons
-#set_property -dict {PACKAGE_PIN D9 IOSTANDARD LVCMOS33} [get_ports btn0]
+set_property -dict {PACKAGE_PIN D9 IOSTANDARD LVCMOS33} [get_ports btn0]
#set_property -dict { PACKAGE_PIN C9 IOSTANDARD LVCMOS33 } [get_ports { btn1 }]; #IO_L11P_T1_SRCC_16 Sch=btn[1]
#set_property -dict { PACKAGE_PIN B9 IOSTANDARD LVCMOS33 } [get_ports { btn[2] }]; #IO_L11N_T1_SRCC_16 Sch=btn[2]
#set_property -dict { PACKAGE_PIN B8 IOSTANDARD LVCMOS33 } [get_ports { btn[3] }]; #IO_L12P_T1_MRCC_16 Sch=btn[3]
diff --git a/tridoracpu/tridoracpu.srcs/irqctrl.v b/tridoracpu/tridoracpu.srcs/irqctrl.v
index 5608440..1a079bf 100644
--- a/tridoracpu/tridoracpu.srcs/irqctrl.v
+++ b/tridoracpu/tridoracpu.srcs/irqctrl.v
@@ -1,6 +1,6 @@
`timescale 1ns / 1ps
-module irqctrl #(IRQ_LINES = 3, IRQ_DELAY_WIDTH = 8) (
+module irqctrl #(IRQ_LINES = 2, IRQ_DELAY_WIDTH = 4) (
input wire clk,
input wire [IRQ_LINES-1:0] irq_in,
input wire cs,
diff --git a/tridoracpu/tridoracpu.srcs/stackcpu.v b/tridoracpu/tridoracpu.srcs/stackcpu.v
index b8ef78c..33b58ec 100644
--- a/tridoracpu/tridoracpu.srcs/stackcpu.v
+++ b/tridoracpu/tridoracpu.srcs/stackcpu.v
@@ -16,11 +16,11 @@ module stackcpu #(parameter ADDR_WIDTH = 32, WIDTH = 32,
output wire write_enable,
input wire mem_wait,
- output wire debug1,
- output wire debug2,
- output wire debug3
+ output wire led1,
+ output wire led2,
+ output wire led3
);
-
+
localparam EVAL_STACK_INDEX_WIDTH = 6;
wire reset = !rst;
@@ -90,6 +90,7 @@ module stackcpu #(parameter ADDR_WIDTH = 32, WIDTH = 32,
wire mem_write;
wire x_is_zero;
+ // wire [WIDTH-1:0] y_plus_operand = Y + operand;
wire x_equals_y = X == Y;
wire y_lessthan_x = $signed(Y) < $signed(X);
@@ -104,10 +105,16 @@ module stackcpu #(parameter ADDR_WIDTH = 32, WIDTH = 32,
assign write_enable = mem_write_enable;
// debug output ------------------------------------------------------------------------------------
- assign debug1 = reset;
- assign debug2 = ins_loadc;
- assign debug3 = ins_branch;
-
+ assign led1 = reset;
+ assign led2 = ins_loadc;
+ assign led3 = ins_branch;
+// assign debug_out1 = { mem_read_enable, mem_write_enable, x_is_zero,
+// ins_branch, ins_aluop, y_lessthan_x, x_equals_y, {7{1'b0}}, seq_state};
+// assign debug_out2 = data_in;
+// assign debug_out3 = nX;
+// assign debug_out4 = nPC;
+// assign debug_out5 = ins;
+// assign debug_out6 = IV;
//--------------------------------------------------------------------------------------------------
// instruction decoding
@@ -399,10 +406,7 @@ module stackcpu #(parameter ADDR_WIDTH = 32, WIDTH = 32,
// process irq
always @(posedge clk)
begin
- // in MEM state, clear irq_pending, when nPC has been set to IV
- // RET instruction is a special case because we need to use
- // the new PC that is in mem_data
- if(seq_state == MEM && irq_pending && !(ins_xfer && xfer_r2p))
+ if(seq_state == MEM && irq_pending && !(ins_xfer & xfer_r2p)) // in FETCH state, clear irq_pending.
irq_pending <= 0;
else
irq_pending <= irq_pending || irq; // else set irq_pending when irq is high
diff --git a/tridoracpu/tridoracpu.srcs/tdraudio.v b/tridoracpu/tridoracpu.srcs/tdraudio.v
index 4ad978d..cef16da 100644
--- a/tridoracpu/tridoracpu.srcs/tdraudio.v
+++ b/tridoracpu/tridoracpu.srcs/tdraudio.v
@@ -1,93 +1,53 @@
`timescale 1ns / 1ps
-// waveform generator module (PCM)
+// waveform generator module (pulse wave or noise)
module wavegen #(DATA_WIDTH=32, CLOCK_DIV_WIDTH=22,
AMP_WIDTH=16, AMP_BIAS=32768) (
input wire clk,
input wire reset,
input wire [1:0] reg_sel,
output wire [DATA_WIDTH-1:0] rd_data,
- input wire [AMP_WIDTH-1:0] wr_data,
+ input wire [DATA_WIDTH-1:0] wr_data,
input wire rd_en,
input wire wr_en,
output wire [AMP_WIDTH-1:0] amp_val,
- output wire running,
- output wire irq
+ output wire running
);
localparam TDRAU_REG_CTL = 0; /* control register */
localparam TDRAU_REG_CLK = 1; /* clock divider register */
localparam TDRAU_REG_AMP = 2; /* amplitude (volume) register */
- /* avoid warning about unconnected port */
- (* keep="soft" *) wire _unused = rd_en;
+// localparam LFSR_WIDTH = 18;
+// localparam LFSR_TAP_IDX_1 = 17;
+// localparam LFSR_TAP_IDX_2 = 10;
+// localparam LFSR_INIT = 'h3CBE6;
+
+ localparam LFSR_WIDTH = 23;
+ localparam LFSR_INIT = 'h1;
reg channel_enable;
reg [CLOCK_DIV_WIDTH-1:0] clock_div;
reg [CLOCK_DIV_WIDTH-1:0] div_count;
reg amp_phase;
+ reg [AMP_WIDTH-1:0] amp_start;
reg [AMP_WIDTH-1:0] amp_out;
+ reg noise_enable;
+ reg [LFSR_WIDTH-1:0] lfsr;
+ wire [AMP_WIDTH-1:0] noise_out;
- wire fifo_wr_en;
- wire fifo_rd_en, fifo_full, fifo_empty;
- wire [AMP_WIDTH-1:0] fifo_rd_data;
-
- fifo #(.ADDR_WIDTH(4), .DATA_WIDTH(16)) sample_buf(
- clk, reset,
- fifo_wr_en, fifo_rd_en,
- wr_data[AMP_WIDTH-1:0], fifo_rd_data,
- fifo_full,
- fifo_empty
- );
-
- 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 [DATA_WIDTH-1:0] rd_data_buf;
- assign rd_data = rd_data_buf;
+ reg direct_amp_enable;
+ //assign rd_data = {{DATA_WIDTH-8-CLOCK_DIV_WIDTH{1'b0}}, div_count, {7{1'b0}}, channel_enable};
+ assign rd_data = {8'b0, amp_start,
+ {6{1'b0}}, amp_phase, channel_enable};
assign amp_val = amp_out;
assign running = channel_enable;
wire ctl_reg_write = wr_en && (reg_sel == TDRAU_REG_CTL);
- /* 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};
- end
-
- /* irq signal to interrupt controller */
- always @(posedge clk)
- begin
- if(reset)
- irq_buf <= 0;
- else
- if(fifo_empty && irq_enable)
- irq_buf <= 1;
- else
- irq_buf <= 0;
- end
-
- /* interrupt enable flag */
- always @(posedge clk)
- begin
- if(reset)
- irq_enable <= 0;
- else
- if(ctl_reg_write)
- irq_enable <= wr_data[4];
- else
- if(irq_buf)
- irq_enable <= 0; // disable interrupts after an interrupt
- end
-
/* channel enable flag */
always @(posedge clk)
begin
@@ -107,6 +67,16 @@ module wavegen #(DATA_WIDTH=32, CLOCK_DIV_WIDTH=22,
clock_div <= wr_data;
end
+ /* amplitude register */
+ always @(posedge clk)
+ begin
+ if(reset)
+ amp_start <= 0;
+ else
+ if (wr_en && (reg_sel == TDRAU_REG_AMP))
+ amp_start <= wr_data;
+ end
+
/* divider counter */
always @(posedge clk)
begin
@@ -122,6 +92,43 @@ module wavegen #(DATA_WIDTH=32, CLOCK_DIV_WIDTH=22,
div_count <= 1; // start cycle on next clock tick
end
+
+ /* noise enable flag */
+ always @(posedge clk)
+ begin
+ if(reset)
+ noise_enable <= 0;
+ else if (ctl_reg_write)
+ noise_enable <= wr_data[1];
+ end
+
+ /* noise generator (Linear Feedback Shift Register) */
+ always @(posedge clk)
+ begin
+ if (reset)
+ lfsr <= LFSR_INIT;
+ else
+ if (ctl_reg_write && wr_data[1])
+ lfsr <= LFSR_INIT;
+ else
+ if (channel_enable && noise_enable)
+ if (div_count == 0)
+ //lfsr <= { lfsr[LFSR_TAP_IDX_1] ^ lfsr[LFSR_TAP_IDX_2], lfsr[LFSR_WIDTH-1:1] };
+ // shift width and tap bits taken from https://github.com/jotego/jtopl
+ lfsr <= { lfsr[LFSR_WIDTH-2:0], lfsr[22] ^ lfsr[9] ^ lfsr[8] ^ lfsr[0]};
+ end
+
+ assign noise_out = lfsr[0] ? amp_start : ~amp_start;
+
+ /* direct amplitude enable flag */
+ always @(posedge clk)
+ begin
+ if(reset)
+ direct_amp_enable <= 0;
+ else if (ctl_reg_write)
+ direct_amp_enable <= wr_data[2];
+ end
+
/* amplitude out */
always @(posedge clk)
begin
@@ -135,7 +142,9 @@ module wavegen #(DATA_WIDTH=32, CLOCK_DIV_WIDTH=22,
begin
if (div_count == 0) // invert amplitude on clock tick
begin
- amp_out <= fifo_rd_data;
+ amp_out <= direct_amp_enable ? amp_start :
+ noise_enable ? noise_out :
+ amp_phase ? amp_start : ~amp_start;
amp_phase <= ~amp_phase;
end
end
@@ -143,8 +152,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
@@ -158,7 +167,7 @@ module tdraudio #(DATA_WIDTH=32) (
input wire [DATA_WIDTH-1:0] wr_data,
input wire rd_en,
input wire wr_en,
- output wire irq_out,
+
output wire pdm_out,
output wire gain_sel,
output wire shutdown_n
@@ -166,21 +175,14 @@ module tdraudio #(DATA_WIDTH=32) (
localparam CLOCK_DIV_WIDTH = 22;
localparam AMP_WIDTH = 16;
- localparam AMP_BIAS = 32768;
localparam DAC_WIDTH = 18;
- /* avoid warning about unconnected port */
- (* keep="soft" *) wire [DATA_WIDTH-1:AMP_WIDTH] _unused = wr_data[DATA_WIDTH-1:AMP_WIDTH];
-
wire [4:0] chan_sel = io_addr[6:2];
wire [1:0] reg_sel = io_addr[1:0];
- wire [AMP_WIDTH-1:0] amp_wr_data = wr_data[AMP_WIDTH-1:0];
-
wire [AMP_WIDTH-1:0] chan0_amp;
wire [DATA_WIDTH-1:0] chan0_rd_data;
wire chan0_running;
- wire chan0_irq;
wire chan0_sel = chan_sel == 5'd0;
wire chan0_rd_en = chan0_sel && rd_en;
wire chan0_wr_en = chan0_sel && wr_en;
@@ -188,7 +190,6 @@ module tdraudio #(DATA_WIDTH=32) (
wire [AMP_WIDTH-1:0] chan1_amp;
wire [DATA_WIDTH-1:0] chan1_rd_data;
wire chan1_running;
- wire chan1_irq;
wire chan1_sel = chan_sel == 5'd1;
wire chan1_rd_en = chan1_sel && rd_en;
wire chan1_wr_en = chan1_sel && wr_en;
@@ -196,7 +197,6 @@ module tdraudio #(DATA_WIDTH=32) (
wire [AMP_WIDTH-1:0] chan2_amp;
wire [DATA_WIDTH-1:0] chan2_rd_data;
wire chan2_running;
- wire chan2_irq;
wire chan2_sel = chan_sel == 5'd2;
wire chan2_rd_en = chan2_sel && rd_en;
wire chan2_wr_en = chan2_sel && wr_en;
@@ -204,13 +204,14 @@ module tdraudio #(DATA_WIDTH=32) (
wire [AMP_WIDTH-1:0] chan3_amp;
wire [DATA_WIDTH-1:0] chan3_rd_data;
wire chan3_running;
- wire chan3_irq;
wire chan3_sel = chan_sel == 5'd3;
wire chan3_rd_en = chan3_sel && rd_en;
wire chan3_wr_en = chan3_sel && wr_en;
wire running = chan0_running || chan1_running || chan2_running || chan3_running;
+ reg was_running;
+
assign rd_data = chan0_sel ? chan0_rd_data :
chan1_sel ? chan1_rd_data :
chan2_sel ? chan2_rd_data :
@@ -218,40 +219,40 @@ module tdraudio #(DATA_WIDTH=32) (
{DATA_WIDTH{1'b1}};
wavegen chan0(clk, reset, reg_sel,
- chan0_rd_data, amp_wr_data,
+ chan0_rd_data, wr_data,
chan0_rd_en, chan0_wr_en,
- chan0_amp,
- chan0_running, chan0_irq);
+ chan0_amp, chan0_running);
wavegen chan1(clk, reset, reg_sel,
- chan1_rd_data, amp_wr_data,
+ chan1_rd_data, wr_data,
chan1_rd_en, chan1_wr_en,
- chan1_amp,
- chan1_running, chan1_irq);
+ chan1_amp, chan1_running);
wavegen chan2(clk, reset, reg_sel,
- chan2_rd_data, amp_wr_data,
+ chan2_rd_data, wr_data,
chan2_rd_en, chan2_wr_en,
- chan2_amp,
- chan2_running, chan2_irq);
+ chan2_amp, chan2_running);
wavegen chan3(clk, reset, reg_sel,
- chan3_rd_data, amp_wr_data,
+ chan3_rd_data, wr_data,
chan3_rd_en, chan3_wr_en,
- chan3_amp,
- chan3_running, chan3_irq);
+ chan3_amp, chan3_running);
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
+ //wire [AMP_WIDTH-1:0] amp_sum_scaled = amp_sum[DAC_WIDTH-2:2]; // shifted right to scale down
assign gain_sel = 1; // gain select: 0 -> 12dB, 1 -> 6dB
- // assign shutdown_n = running;
- assign shutdown_n = 1; /* don't enable shutdown mode, it creates a mains hum */
+ assign shutdown_n = running;
- reg irq_out_buf;
- assign irq_out = irq_out_buf;
-
- always @(posedge clk) irq_out_buf <= chan0_irq || chan1_irq || chan2_irq || chan3_irq;
+ /* detect shutdown */
+ always @(posedge clk)
+ begin
+ if (reset)
+ was_running <= 0;
+ else
+ was_running <= running;
+ end
/* delta-sigma DAC */
always @(posedge clk)
@@ -259,10 +260,11 @@ module tdraudio #(DATA_WIDTH=32) (
if(reset)
deltasigma_acc <= 0;
else
-// if (running)
+ if (running)
deltasigma_acc <= deltasigma_acc[DAC_WIDTH-1:0] + amp_sum;
-// else
-// deltasigma_acc <= deltasigma_acc[DAC_WIDTH-1:0] + (4*AMP_BIAS);
+ else
+ if (!running && was_running) // clear accumulator on shutdown
+ deltasigma_acc <= 0;
end
/* 1-bit audio output */
diff --git a/tridoracpu/tridoracpu.srcs/top.v b/tridoracpu/tridoracpu.srcs/top.v
index bf3bea8..4d0135e 100644
--- a/tridoracpu/tridoracpu.srcs/top.v
+++ b/tridoracpu/tridoracpu.srcs/top.v
@@ -15,6 +15,9 @@
module top(
input wire clk,
input wire rst,
+ input wire btn0,
+ input wire sw0,
+ input wire sw1,
output wire led0,
output wire led1,
output wire led2,
@@ -137,7 +140,7 @@ module top(
assign fb_wr_data = mem_write_data;
vgafb vgafb0(`clock, pixclk, rst,
- mem_addr[5:2], fb_rd_data, fb_wr_data,
+ mem_addr[3:0], fb_rd_data, fb_wr_data,
fb_rd_en, fb_wr_en,
VGA_HS_O, VGA_VS_O, VGA_R, VGA_G, VGA_B);
`endif
@@ -225,21 +228,19 @@ module top(
assign uart_tx_data = mem_write_data[7:0];
assign uart_rd_data = { {WIDTH-10{1'b1}}, uart_rx_avail, uart_tx_busy, uart_rx_data };
- wire audio_irq;
+ // interrupt controller
+ reg timer_tick;
+ reg[23:0] tick_count;
+ wire [1:0] irq_in = { timer_tick, uart_rx_avail };
+ wire [1:0] irqc_rd_data0;
+ wire [WIDTH-1:0] irqc_rd_data = { tick_count, 6'b0, irqc_rd_data0 };
+ wire irqc_seten = mem_write_data[7];
+ wire irqc_cs = io_enable && (io_slot == 3);
- buart #(.CLKFREQ(`clkfreq)) uart0(`clock, rst,
- uart_baud,
- uart_txd_in, uart_rxd_out,
- uart_rx_clear, uart_tx_en,
- uart_rx_avail, uart_tx_busy,
- uart_tx_data, uart_rx_data);
-
- // audio controller
`ifdef ENABLE_TDRAUDIO
wire [WIDTH-1:0] tdraudio_wr_data;
wire [WIDTH-1:0] tdraudio_rd_data;
wire tdraudio_rd_en, tdraudio_wr_en;
- wire tdraudio_irq;
wire tdraudio_cs_en = io_enable && (io_slot == 4);
assign tdraudio_rd_en = tdraudio_cs_en && mem_read_enable;
@@ -247,25 +248,14 @@ module top(
assign tdraudio_wr_data = mem_write_data;
tdraudio tdraudio0(`clock, ~rst,
- mem_addr[8:2],
+ mem_addr[6:0],
tdraudio_rd_data,
tdraudio_wr_data,
tdraudio_rd_en,
tdraudio_wr_en,
- tdraudio_irq,
amp2_ain, amp2_gain, amp2_shutdown_n);
- assign audio_irq = tdraudio_irq;
`endif
- // interrupt controller
- reg timer_tick;
- reg[23:0] tick_count;
- wire [2:0] irq_in = { audio_irq, timer_tick, uart_rx_avail };
- wire [2:0] irqc_rd_data0;
- wire [WIDTH-1:0] irqc_rd_data = { tick_count, 5'b0, irqc_rd_data0 };
- wire irqc_seten = mem_write_data[7];
- wire irqc_cs = io_enable && (io_slot == 3);
-
assign io_rd_data = (io_slot == 0) ? uart_rd_data :
`ifdef ENABLE_MICROSD
(io_slot == 1) ? spi_rd_data :
@@ -278,9 +268,13 @@ module top(
(io_slot == 4) ? tdraudio_rd_data:
`endif
-1;
- irqctrl irqctrl0(`clock, irq_in, irqc_cs, mem_write_enable,
- irqc_seten, irqc_rd_data0,
- irq);
+
+ buart #(.CLKFREQ(`clkfreq)) uart0(`clock, rst,
+ uart_baud,
+ uart_txd_in, uart_rxd_out,
+ uart_rx_clear, uart_tx_en,
+ uart_rx_avail, uart_tx_busy,
+ uart_tx_data, uart_rx_data);
// CPU -----------------------------------------------------------------
stackcpu cpu0(.clk(`clock), .rst(rst), .irq(irq),
@@ -289,8 +283,12 @@ module top(
.read_ins(dram_read_ins),
.data_out(mem_write_data), .write_enable(mem_write_enable),
.mem_wait(mem_wait),
- .debug1(led1), .debug2(led2), .debug3(led3));
+ .led1(led1), .led2(led2), .led3(led3));
+ // Interrupt Controller
+ irqctrl irqctrl0(`clock, irq_in, irqc_cs, mem_write_enable,
+ irqc_seten, irqc_rd_data0,
+ irq);
// count clock ticks
// generate interrupt every 20nth of a second
diff --git a/tridoracpu/tridoracpu.srcs/vgafb.v b/tridoracpu/tridoracpu.srcs/vgafb.v
index 49dad2d..f87e514 100644
--- a/tridoracpu/tridoracpu.srcs/vgafb.v
+++ b/tridoracpu/tridoracpu.srcs/vgafb.v
@@ -1,9 +1,6 @@
`timescale 1ns / 1ps
`default_nettype none
-// enable shifter/masker registers
-`define ENABLE_FB_ACCEL
-
// Project F: Display Timings
// (C)2019 Will Green, Open Source Hardware released under the MIT License
// Learn more at https://projectf.io
@@ -129,14 +126,6 @@ module vgafb #(VMEM_ADDR_WIDTH = 15, VMEM_DATA_WIDTH = 32) (
localparam REG_PAL_SLOT = 3; localparam REG_PAL_DATA = 4;
localparam REG_CTL = 5;
-`ifdef ENABLE_FB_ACCEL
- localparam REG_SHIFTER = 6;
- localparam REG_SHIFTCOUNT = 7;
- localparam REG_SHIFTERM = 8;
- localparam REG_SHIFTERSP = 09;
- localparam REG_MASKGEN = 10;
-`endif
-
localparam COLOR_WIDTH = 12;
localparam PALETTE_WIDTH = 4;
@@ -156,32 +145,12 @@ module vgafb #(VMEM_ADDR_WIDTH = 15, VMEM_DATA_WIDTH = 32) (
wire pix_rd;
wire [VMEM_DATA_WIDTH-1:0] status;
-`ifdef ENABLE_FB_ACCEL
- reg [VMEM_DATA_WIDTH-1:0] acc_shifter_in;
- reg [(VMEM_DATA_WIDTH*2)-1:0] acc_shifter_out;
- reg [4:0] acc_shift_count;
- reg acc_start_shift;
- reg [VMEM_DATA_WIDTH-1:0] acc_mask_in;
- reg [VMEM_DATA_WIDTH-1:0] acc_mask_buf;
- reg [VMEM_DATA_WIDTH-1:0] acc_shiftmask_buf;
- wire [VMEM_DATA_WIDTH-1:0] acc_shifter_mask = acc_shiftmask_buf;
- wire [VMEM_DATA_WIDTH-1:0] acc_shifter_out_h = acc_shifter_out[(VMEM_DATA_WIDTH*2)-1:VMEM_DATA_WIDTH];
- wire [VMEM_DATA_WIDTH-1:0] acc_shifter_out_l = acc_shifter_out[VMEM_DATA_WIDTH-1:0];
-
- `endif
-
assign vmem_rd_en = rd_en;
assign vmem_wr_en = (reg_sel == REG_VMEM) && wr_en;
assign rd_data = (reg_sel == REG_VMEM) ? vmem_rd_data :
(reg_sel == REG_RD_ADDR) ? cpu_rd_addr :
(reg_sel == REG_WR_ADDR) ? cpu_wr_addr :
(reg_sel == REG_CTL) ? status :
-`ifdef ENABLE_FB_ACCEL
- (reg_sel == REG_SHIFTER) ? acc_shifter_out_h:
- (reg_sel == REG_SHIFTERM) ? acc_shiftmask_buf :
- (reg_sel == REG_SHIFTERSP) ? acc_shifter_out_l :
- (reg_sel == REG_MASKGEN) ? acc_mask_buf :
- `endif
32'hFFFFFFFF;
wire [VMEM_ADDR_WIDTH-1:0] cpu_addr = vmem_wr_en ? cpu_wr_addr : cpu_rd_addr;
@@ -302,74 +271,6 @@ module vgafb #(VMEM_ADDR_WIDTH = 15, VMEM_DATA_WIDTH = 32) (
if(rd_en && reg_sel == REG_VMEM) cpu_rd_addr <= cpu_rd_addr + 1; // auto-increment read addr on read
end
-`ifdef ENABLE_FB_ACCEL
- //
- // shifter/masker registers
- //
- always @(posedge cpu_clk)
- begin
- if(wr_en && reg_sel == REG_SHIFTER)
- acc_shifter_in <= wr_data;
- end
-
- always @(posedge cpu_clk)
- begin
- if(wr_en && reg_sel == REG_SHIFTCOUNT)
- begin
- acc_shift_count <= { wr_data[2:0], 2'b0};
- acc_start_shift <= 1;
- end
-
- if(acc_start_shift)
- acc_start_shift <= 0;
- end
-
- always @(posedge cpu_clk)
- begin
- if (acc_start_shift)
- acc_shifter_out <= {acc_shifter_in, {VMEM_DATA_WIDTH{1'b0}}} >> acc_shift_count;
- end
-
- // mask register
- always @(posedge cpu_clk)
- begin
- if (wr_en && reg_sel == REG_MASKGEN)
- acc_mask_in <= wr_data;
- end
-
- // mask output is buffered to avoid timing problems
- always @(posedge cpu_clk)
- begin
- acc_mask_buf <= {
- {4{|{acc_mask_in[31:28]}}},
- {4{|{acc_mask_in[27:24]}}},
- {4{|{acc_mask_in[23:20]}}},
- {4{|{acc_mask_in[19:16]}}},
- {4{|{acc_mask_in[15:12]}}},
- {4{|{acc_mask_in[11:8]}}},
- {4{|{acc_mask_in[7:4]}}},
- {4{|{acc_mask_in[3:0]}}}
- };
- end
-
- always @(posedge cpu_clk)
- begin
- acc_shiftmask_buf = {
- {4{|{acc_shifter_out_h[31:28]}}},
- {4{|{acc_shifter_out_h[27:24]}}},
- {4{|{acc_shifter_out_h[23:20]}}},
- {4{|{acc_shifter_out_h[19:16]}}},
- {4{|{acc_shifter_out_h[15:12]}}},
- {4{|{acc_shifter_out_h[11:8]}}},
- {4{|{acc_shifter_out_h[7:4]}}},
- {4{|{acc_shifter_out_h[3:0]}}}
- };
- end
-`endif
-
- //
- // shifting pixels at pixel clock
- //
always @(posedge pix_clk)
begin
if(scanline || shift_count == MAX_SHIFT_COUNT) // before start of a line
diff --git a/tridoracpu/tridoracpu.xpr b/tridoracpu/tridoracpu.xpr
index 5d8ff88..15b43f2 100644
--- a/tridoracpu/tridoracpu.xpr
+++ b/tridoracpu/tridoracpu.xpr
@@ -378,20 +378,30 @@
-
+
-
- Default settings for Implementation.
+
+ Uses multiple algorithms for optimization, placement, and routing to get potentially better results.
-
+
+
+
-
+
+
+
-
-
+
+
+
+
+
+
-
+
+
+
diff --git a/utils/serload.py b/utils/serload.py
index 0ee6962..6ccc4a6 100644
--- a/utils/serload.py
+++ b/utils/serload.py
@@ -16,7 +16,6 @@
# limitations under the License.
import sys
-import os
import serial
import time
import random
@@ -42,6 +41,30 @@ def get_default_device():
return '/dev/ttyUSB1'
+def serwrite_slow(databytes, ser):
+ total = len(data)
+ count = 1
+ for d in data:
+ sys.stdout.write("writing {0:02x} {1:04d}/{2:04d}\r".format(ord(d), count, total))
+ ser.write(bytes(d,"utf8"))
+ count += 1
+ time.sleep(0.020)
+ print()
+
+
+def serwrite(datafile, ser):
+ with open(datafile) as f:
+ data = f.read()
+ total = len(data)
+ count = 1
+ for d in data:
+ sys.stdout.write("writing {0:02x} {1:04d}/{2:04d}\r".format(ord(d), count, total))
+ ser.write(bytes(d,"utf8"))
+ count += 1
+ time.sleep(0.020)
+ print()
+
+
def checksum(databytes):
i = 0
cksum = 0
@@ -62,29 +85,10 @@ def sendchar(char, ser):
ser.write(char.to_bytes(1, 'big'))
-def sendcommand(ser, cmd=b'L', verbose=False):
- verbose = True
+def sendcommand(ser, cmd=b'L'):
ser.write(cmd)
resp = ser.read_until()
- if verbose:
- print(cmd,"sent, response:", str(resp))
- return resp
-
-
-# send command and wait for echo
-def commandwait(ser, cmd):
- resp = sendcommand(ser, cmd, verbose=False)
- if len(resp) == 0:
- print("timeout sending '{}' command".format(cmd))
- return None
-
- if resp.startswith(b"> "):
- resp = resp[2:]
-
- if resp != bytearray(cmd + b"\r\n"):
- print("invalid response to '{}' command".format(cmd))
- return None
-
+ print(cmd,"sent, response:", str(resp))
return resp
@@ -149,8 +153,6 @@ def serload_bin(datafile, ser):
data += bytearray(pad)
- print("{} total blocks".format((len(data) + blocksize - 1) // blocksize))
-
if not send_size_header(ser, filesize):
print("Error sending size header.")
return
@@ -277,8 +279,18 @@ def serdownload(fname, ser):
def mput(filenames, ser):
for f in filenames:
- resp = set_filename(f, ser)
- if resp is None:
+ f_encoded = f.encode('utf8')
+ print("Setting filename", f)
+ resp = sendcommand(ser, b'S')
+ if len(resp) == 0:
+ print("timeout sending 'S' command")
+ return
+ if resp != b'S\r\n' and resp != b'> S\r\n':
+ print("unrecognized response to 'S' command, aborting")
+ return
+ resp = sendcommand(ser, f_encoded + b'\r')
+ if not f_encoded in resp:
+ print("unrecognized response to filename, aborting")
return
serload_bin(f, ser)
@@ -287,94 +299,12 @@ def mput(filenames, ser):
time.sleep(2)
-def set_filename(f, ser):
- f_encoded = f.encode('utf8')
- print("Setting filename", f)
- resp = commandwait(ser, b'S')
- if resp is None:
- return None
- resp = sendcommand(ser, f_encoded + b'\r')
- if not f_encoded in resp:
- print("unrecognized response to filename, aborting")
- return None
- return resp
-
-
-def getnamedfile(filename, ser):
- resp = set_filename(filename, ser)
- if resp is None:
- return None
- serdownload(filename, ser)
-
-
-def putnamedfile(filename, ser):
- resp = set_filename(filename, ser)
- if resp is None:
- return None
- serload_bin(filename, ser)
- print("Remote status:")
- showdata(ser)
-
-
-def showdata(ser):
-
- promptseen = False
-
- while not promptseen:
- c = ser.read(1)
- if c == b'>':
- promptseen = True
- else:
- print(c.decode('utf8'), end='')
- rest = ser.read(1) # read trailing space of prompt
-
-
-def localdir():
- result = os.walk(".")
- for dirpath, dirnames, filenames in os.walk("."):
- for f in filenames:
- print(f)
- break
-
-
-def interactive(ser):
- done = False
- while not done:
- args = input("> ").strip().split()
- if len(args) > 0:
- cmd = args[0]
- args.pop(0)
- if cmd == 'dir':
- if commandwait(ser, b'Y') is None:
- return
- showdata(ser)
- elif cmd == 'get':
- if len(args) > 1:
- print("exactly one argument required (filename)")
- else:
- getnamedfile(args[0], ser)
- elif cmd == 'put':
- if len(args) > 1:
- print("exactly one argument required (filename)")
- else:
- putnamedfile(args[0], ser)
- elif cmd == 'ldir':
- if len(args) > 0:
- print("superfluous argument")
- else:
- localdir()
- elif cmd == 'exit' or cmd == 'x':
- done = True
- else:
- print("Unknown command. Valid commands are: dir get ldir put exit")
-
-
if __name__ == "__main__":
argparser = argparse.ArgumentParser(
description='transfer files from/to the Tridora-CPU')
argparser.add_argument('-d', '--device', help='serial device', default=get_default_device())
- argparser.add_argument('command', choices=['get', 'put', 'mput', 'interactive'])
- argparser.add_argument('filename', nargs='*')
+ argparser.add_argument('command', choices=['get', 'put', 'mput'])
+ argparser.add_argument('filename', nargs='+')
args = argparser.parse_args()
cmd = args.command
@@ -389,10 +319,8 @@ if __name__ == "__main__":
serload_bin(filenames[0], ser)
elif cmd == 'mput':
mput(filenames, ser)
- elif cmd == 'interactive':
- interactive(ser)
else:
print("should not get here")
- #if cmd is not None:
- # ser.close()
+ if cmd is not None:
+ ser.close()
diff --git a/utils/tdrimg.py b/utils/tdrimg.py
index 4eeaead..be93ed9 100644
--- a/utils/tdrimg.py
+++ b/utils/tdrimg.py
@@ -538,9 +538,6 @@ def create_image_with_stuff(imgfile):
slotnr = putfile("../progs/recover.prog", None , f, part, partstart, slotnr)
slotnr = putfile("../progs/changemem.prog", None , f, part, partstart, slotnr)
- slotnr = putfile("../lib/pcmaudio.s", None , f, part, partstart, slotnr)
- slotnr = putfile("../lib/pcmaudio.inc", None , f, part, partstart, slotnr)
-
listdir(f, part)
# third partition
@@ -603,8 +600,6 @@ def create_image_with_stuff(imgfile):
slotnr = putfile("../examples/lines.pas", None , f, part, partstart, slotnr)
- slotnr = putfile("../examples/pcmtest2.pas", None , f, part, partstart, slotnr)
-
slotnr = putfile("../examples/pictviewer.pas", None , f, part, partstart, slotnr)
slotnr = putfile("../examples/Toco_Toucan.pict", None , f, part, partstart, slotnr)
slotnr = putfile("../examples/shinkansen.pict", None , f, part, partstart, slotnr)
@@ -614,7 +609,6 @@ def create_image_with_stuff(imgfile):
slotnr = putfile("../examples/benchmarks.pas", None , f, part, partstart, slotnr)
slotnr = putfile("../examples/animate.pas", None , f, part, partstart, slotnr)
- slotnr = putfile("../examples/graphbench.pas", None , f, part, partstart, slotnr)
slotnr = putfile("../examples/sprites.inc", None , f, part, partstart, slotnr)
slotnr = putfile("../examples/sprites.s", None , f, part, partstart, slotnr)
slotnr = putfile("../examples/background.pict", None , f, part, partstart, slotnr)
diff --git a/utils/wav2tdrau.py b/utils/wav2tdrau.py
deleted file mode 100644
index 16230d6..0000000
--- a/utils/wav2tdrau.py
+++ /dev/null
@@ -1,29 +0,0 @@
-import sys
-import random, struct
-import wave
-
-freq = 16000
-BIAS = 32768
-def convert(srcpath, destpath):
- outdata = bytearray()
- with wave.open(srcpath, mode="rb") as f:
- params = f.getparams()
- print(params.nchannels, params.sampwidth, params.framerate)
-
- frames = f.readframes(2*1024*1024)
- for i in range(0, len(frames), 2):
- v = int.from_bytes(frames[i:i+2], "little", signed=True)
- v += BIAS
- hi = (v & 0xFF00) >> 8
- lo = (v & 0x00FF)
- outdata.append(hi)
- outdata.append(lo)
-
- with open(destpath, mode="wb") as f:
- f.write(outdata)
-
-
-if __name__ == "__main__":
- sourcefilename = sys.argv[1]
- destfilename = sys.argv[2]
- convert(sourcefilename, destfilename)