sy2002 / qnice-fpga Goto Github PK
View Code? Open in Web Editor NEWQNICE-FPGA is a 16-bit computer system for recreational programming built as a fully-fledged System-on-a-Chip in portable VHDL.
Home Page: http://qnice-fpga.com
License: Other
QNICE-FPGA is a 16-bit computer system for recreational programming built as a fully-fledged System-on-a-Chip in portable VHDL.
Home Page: http://qnice-fpga.com
License: Other
The instruction
MOVE 0x00FF, R14
works differently on the emulator and the hardware.
On the emulator, all flags (in particular the overflow flag V) are set.
On the hardware, the overflow flag is not set.
In the file qnice_cpu.vhd
in lines 580-587 I see the comment:
-- not all parts of the SR are writeable: only the upper 8 bit plus
-- the M, C and X register are writeable,
So what is the 'correct' behaviour? And what is the 'M' flag ? I don't see it mentioned anywhere in the QNICE introduction document.
@MJoergen I personally would be excited a lot about the VGA topic. But just in case: Here in TODO.txt are some more topics that you might want to have a look at for V1.7. In case you find something that you want to do: Just make an issue and assign it to yourself. In that case, please delete the item from TODO.txt
as we try not to have redundancy between the issues list in GitHub and the TODO.txt
. The latter one is more like a longterm "backlog"...
Please close this issue when you're done (independent from if you found anything in TODO.txt
or not)
P.S. Of course feel free to add your own ideas to TODO.txt
(longterm backlog) as well as to the GitHub issues.
This one is not urgent as the use case would also need writeable SD cards, FAT32 to support writing and possibly also support for more RAM:
The idea is: One day to be able to develop for QNICE on the QNICE. For example do write and assemble QNICE assembler while working on QNICE hardware.
Besides the fact that for that we also would need a nice assembler text editor on QNICE (or even an QNICE assmbler IDE ๐ ): We need the assembler to run on QNICE.
And for that we need to make it "stand-alone", i.e. independent from an external C preprocessor.
How to reproduce:
Experiment 1: run test_programs/timer_test.asm
(which works on the hardware) on the emulator: Neither timer0 nor timer1 will start
Experiment 2: comment out the invokation of timer1 (by not having any ISR written) and rename the timer0 registers to timer1 => timer1 will not start
@MJoergen let's use this issue to get the refactored and much more elegant mmio_mux working.
Originally, there was pull request #16, but this lead to very strange behaviours of the keyboard. So I reverted the PR back to the old design. Here is the problem description that can also be found in PR #16:
I merged the PR, synthesized with Vivado and then run into a strange effect, when performing some additional tests on my loccal Nexys4DDR hardware.
Let's start first with what works fine:
eae.asm
, cpu_test.asm
and ise.asm
: I retested: Works.regbank.asm
: Works.Here is the strange effect I observe on the PS2/USB keyboard: Many times, I need to hit keys 3-4 times until they are registered. Example: When trying to load Q-Tris from the SD Card, I need to enter normally F
L
qbin/q-tris.out
but now I need to enter F
LL
qqqbin///q--trisss...outtt
, i.e. I sometimes (not predictable when and which key) need to repeat the keys.
When I revert the PR to the old design and synthesize again, then it works fine.
So for now, I reverted the develop branch back to the old design.
Since I consider your design as much more elegant, it would be great, if we could hunt down this bug together :-)
At this moment in time I am stunned:
Is your new elegant design maybe faster than my old one and uncovered a timing problem or other kind of glitch that was sleeping in our code since years?
Or do we all just overlook some obvious typo?
Always fascinating how hard FPGA development is compared to software development ๐
I created the CONTRIBUTING.md at the master
branch, because I thought it belongs there and it might take quite a while until we make our next release (aka update master
with real code).
@MJoergen and @bernd-ulmann Please review CONTRIBUTING.md: If you find obvious errors, please correct them directly in the file.
Also, if you have useful additions, please update the file directly.
If there are controversial points - let's discuss them here in this issue.
@MJoergen I invited you to this repo for full write acccess - welcome! ๐
P.S. Some of the links in CONTRIBUTING.md are right now (as a temporary compromise solution) pointing to files in the develop
branch, just because - as written above - it might take a while until we make the next release V1.6
.
This test should verify that the CPU performs the correct read's and write's on the external bus. This is important when addressing I/O devices, and this issue is created as a result of this comment: #9 (comment).
This issue is non-trivial to implement, and is therefore separate from the existing CPU test suite discussed in Issue #9.
Below are the ideas I have so far. I welcome any feedback, improvements, critique, etc. I propose this issue be targeted for release V1.7, simply because we already have a lot of stuff in V1.6.
A new I/O device will be developed (in both hardware and the emulator) with the following register map:
0xFF80 : Regular R/W scratch register
0xFF81 : Regular R/W scratch register
0xFF82 : Unused (?)
0xFF83 : Unused (?)
0xFF84 : Counts number of reads from 0xFF80. Writeable
0xFF85 : Counts number of reads from 0xFF81. Writeable
0xFF86 : Counts number of writes to 0xFF80. Writeable
0xFF87 : Counts number of writes to 0xFF81. Writeable
The test code will look something like:
MOVE 0xFF81, R1
CMP 0, @--R1
The above code is expected to perform 1 read from 0xFF80, and no writes. So the test will clear all counters, then perform the above two instructions, and then verify the four counters have the correct values.
The test will then repeat with all instructions and all pairs of addressing modes.
Document programming conventions like INCRB/DECRB in sub-routines and making sure the register bank "pointer" points always to the highest used bank, do not program "look aheads"
R8 as default return value for functions
ISRs must not alter any register (use the stack to save/restore)
sysdef.asm for convenient abbreviations
Monitor "OS" calls
; for comments in assembler
optimal columns (take Q-TRIS as example)
name it best-practices and title it "Programming Conventions and Best-Practices"
TODO: doc/best-practices.md
Shrink the ROM, currently we could go from 0x0000 to 0x1FFF and still have plenty of room left and let programs start at 0x2000, instead of as this is the case today, from 0x8000 on.
TODO: Before starting with this issue, we need to make a list with obvious and not-so obvious ramifications. Examples:
The ubiquitous usage of RBRA
"everywhere" needs to be rethought: RBRA can only jump 32k words forward and backward. This does not matter, as long as programs start at 0x8000
but it does matter, when we switch to 0x2000
. So in this example, the minimum we would need to do: Add a warning to the assembler, when one wants to RBRA
farther ahead than possible and think again of other ramifiations.
VBCC currently hardcodes 0x8000
at various places in the toolchain
For sure there are a ton more of these nitty-grity details that follow from this issue, so handle with care (and preferably do it in a separate branch)
The assembler issues no error message in case of a .DW directive which uses an undefined label. Something like
.ORG 0x8000
.DW BLA
yields 0x7FFE in address 0x8000 while it should yield an error.
I added a hardware instruction counter and a hardware cycle counter to QNICE-FPGA, so that we can do performance tests. Here is a simple and minimal test program:
https://github.com/sy2002/QNICE-FPGA/blob/develop/test_programs/ise.asm
What happens:
When synthesizing with Vivado, the correct values are being output from the test program. When synthesizing using ISE, complete rubbish is being outout.
Here is the hardware:
https://github.com/sy2002/QNICE-FPGA/blob/develop/vhdl/cycle_counter.vhd
For being on the safe side: Clone a fresh QNICE-FPGA repo, switch
to the branch develop (git checkout develop). (Not to be mixed up with dev-int. It needs to be develop)
Compile the toolchain: Run tools/make-toolchain.sh
Compile the monitor: Run monitor/compile_and_distribute.sh
Compile the PORE ROM: Run pore/compile_pore.sh
Go to test_programs
and run ../assembler/asm ise.asm
. You will need
the resulting .out
file in the following experiment.
Use hw/xilinx/nexys4ddr/Vivado/qnice_nexys.xpr
to synthesize a bitstream:
All good, incl. timing closure.
Start it on hardware
Run the above-mentioned ise.out on hardware
Everything will work like a charm and you will see a hexadecimal output like
this:
Amount of cycles used: 000000000041
Amount of instructions performed: 000000000012
Use hw/xilinx/nexys4ddr/ISE/env1.xise
to synthesize a bitstream:
All will work fine, too. Incl. timing closure.
Start it on hardware
Run the above-mentioned ise.out on hardware
WOW. Nothing works. You will see an output like
Amount of cycles used: FFFCFFFCFFFC
Amount of instructions performed: FFFCFFFCFFFC
Change the speed grade of the Nexys in ISE
Cut the clk speed (50 MHz) in half (25 MHz)
Read multiple times from the same register to check, if there is a timing problem (doesn't seem to be)
Changed (just for testing purposes and reverted back immediatelly) the register bank to synchroneous BRAM. This is in general not a good idea, because then the cpu_test.asm fails and the whole architecture of the CPU would need to be changed, but I just wanted to see, if this might be the reason.
For 1.7 (or later): As described by Michael in issue #4 ISE vs. Vivado Riddle and #22 Refactor mmio_mux, the fact that we have this nice inout
data bus plus the tristate buffers seem to be the reason for more stress and trouble, than it is good.
So we need to refactor this and I suggest that Michael is doing it in V1.7 or later using a new branch then which is a descendant of the then up-to-date develop
branch.
The source code of the emulator seems to suggest that MOVE instructions should not affect the C (carry) and V (overflow) flags. This is implied from this line of code in qnice.c:
update_status_bits(destination, destination, destination, DO_NOT_MODIFY_CARRY | DO_NOT_MODIFY_OVERFLOW);
However, the MOVE instruction DOES actually modify the C and V flags in that it clears them. This can be most easily seen by running the following sequence of instructions:
MOVE 0x8765, R0
ADD 0x9876, R0
; Now C and V are set
MOVE 0x0000, R0
; Now C and V have been cleared again
The document qnice_intro.pdf
does not give any specific details other than words like "last result" and "last operation". I haven't found any more detailed documentation regarding which instructions affect which status flags, so it's not clear to me what the correct behaviour is, but the source code of the emulator is misleading.
Note: This is seen in the latest develop
branch.
This code snippet leads to a segfault in the assembler:
SYSCALL(puthex, 8)
Obviously, it does not like my typo ,8
:-) The output looks like this:
TITANIUM-M5:test_programs$ ../assembler/asm timer_test.asm
assemble: Line 546: Illegal condition flag! ( ASUB puthex, 8)
../assembler/asm: line 36: 83225 Segmentation fault: 11 $assembler $temp_file $destination
Branch for the fix: dev-int
because there, the newest assembler (enhanced while adding the interrupt features) should be located
This will simplify the release process, by not having to update these values manually.
Checking out the latest dev-io-addr
branch and compiling the emulator leads to the following error:
timer.c:(.text+0x1aa): undefined reference to `pthread_create'
One possible fix to this is to replace (in make.bash
) the line
$COMPILER $FILES -O3 $DEF_SWITCHES $UNDEF_SWITCHES -o qnice
with
$COMPILER $FILES -O3 $DEF_SWITCHES $UNDEF_SWITCHES -pthread -o qnice
Whether this is the correct solution (i.e. whether it works on other Linux distributions) I don't know. I'm using Linux Mint 19.3 (derived from Ubuntu).
When building for the Nexys4DDR target using Vivado, and viewing the Methodology report gives a number of critical warnings, including:
count
in cycle_counter.vhd
.write_eae_registers
in EAE.vhd
.Quite generally, it is recommended to use synchronous reset rather than asynchronous reset when developing for FPGA, particularly if the asynchronous reset is driven by a LUT, as this could potentially lead to race conditions. However, changing all source files is a major (and non-trivial and potentially bug-introducing) task and requires re-testing everything. Item 2 is mentioned above because Vivado claims to get better optimization possibilities after the change.
So I propose for now that only the two items mentioned above be considered for now. They are rather easy to fix (in the sense that they only require touching a few files), and rather easy to test separately (using eae.asm
and ise.asm
).
Should this be pushed to the develop
branch immediately? I don't think this will cause any merge problems.
It is conceivable (I say hopefully ...) that item 1 above might fix Issue #4 considering that issue is precisely related to the cycle counters.
@bernd-ulmann Emulator crashes on EAE (?) in sierpinski.c in branch dev-io-addr
. So this might be a problem related to the new MMIO address map.
Reproduction:
dev-io-addr
branch so that you have the correct standard C lib (with the updated MMIO address map)monitor/compile_and_distribute.sh
so that you have the correct/updated MMIO address map in dist_kit and that your local monitor.out is freshc
and enter source setenv.source
c/test_programs
and enter qvc qvc sierpinski.c -c99
emulator
folder and enter ./make.bash
/qnice
load ../monitor/monitor.out
load ../c/test_programs/sierpinski.out
run 0
C``R
8000
495,3,3
You will receive a floating point exception.
TITANIUM-M5:emulator mirko$ ./qnice
Q> load load ../monitor/monitor.out
Unable to open file >>load<<
Q> load load ../monitor/monitor.out^C
Q> load ../monitor/monitor.out
Q> load ../c/test_programs/sierpinski.out
Q> run
Simple QNICE-monitor - Version 0.8 (Bernd Ulmann, sy2002, July 2020)
------------------------------------------------------------------------
QMON> CONTROL/RUN ADDRESS=8000
Sierpinski Fractal Generator
by LambdaBeta in August 2015, adjusted for QNICE by sy2002 in October 2016
Enter bitpattern, scale (2 .. 5) and generation count (0 .. 5).
Here are some value pairs that produce nice results:
[b, s, g] = 495, 3, 3
[b, s, g] = 7, 2, 5
[b, s, g] = 186, 3, 3
[b, s, g] = 495,3,3
Floating point exception: 8
The following sequence of instructions:
MOVE 0x8765, R1
MOVE 0x00FF, R14
HALT ; Now X correctly contains 1
SHR 0x0001, R1
HALT ; Now X correctly contains 1
SHR 0x0000, R1
HALT ; Now X still contains 1, but should be cleared
leads to X not being cleared as it should. Or should it be unchanged?
Furthermore, the R14 register contains garbage as seen from the following run. It therefore looks like there is an uninitialized variable when shifting by a zero amount. Perhaps the call to write_register()
should not take place in this situation?
Q> rdump
Register dump: BANK = 00, SR = MIVNZCX1
R00-R03: 879f 8765 0000 0000
R04-R07: 0000 0000 0000 0000
R08-R11: 8000 0be1 0000 0000
R12-R15: 0000 feeb 00ff 8005
Q> run 0x8005
HALT instruction executed at address 8007.
Q> rdump
Register dump: BANK = 00, SR = MIVNZCX1
R00-R03: 879f c3b2 0000 0000
R04-R07: 0000 0000 0000 0000
R08-R11: 8000 0be1 0000 0000
R12-R15: 0000 feeb 00ff 8008
Q> run 0x8008
HALT instruction executed at address 800A.
Q> rdump
Register dump: BANK = 170f12, SR = MIVNZC_1
R00-R03: 0000 c3b2 0000 0000
R04-R07: 0000 0000 0000 0000
R08-R11: 8000 0be1 0000 0000
R12-R15: 0000 feeb 170f12fd 800b
Implement a Memory Management Unit
Step 1: Make architecture
More steps tbd
In the last few days, beginning from August 7, on the (not in use any more) branch dev-io-addr
, Bernd and Michael worked together to improve the quality of the emulator to fit better to the super thorough (and great) test_programs/cpu_test.asm
.
But this came at a price, as mentioned in issue #52: We broke the SD Card code, the FAT32 code and Q-TRIS at an unpredictable amount of lines of code. Just for your reference, here is the line count of the affected files:
TITANIUM-M5:QNICE-FPGA sy2002$ wc -l demos/q-tris.asm monitor/sd_library.asm monitor/fat32_library.asm
2228 demos/q-tris.asm
131 monitor/sd_library.asm
2134 monitor/fat32_library.asm
4493 total
And: We might have even more affected files, because my smoke test was super short.
One thing is clear: I will not sift alone through 4493+ lines of code in search for obscure bugs. It can take ages. The FAT32 stuff is non-trivial and also Q-TRIS has its complicated parts. This needs to be a team effort or we need to be smart (and/or revert some decisions to change the behaviour and declare them as "this is how the ISA works ;-) )
It is good, that the three of us will meet soon in an online meeting, because the right way forward in this situation is not obvious and also not trivial, so that I think a verbal discussion / video call is much better then a written discussion in this issue.
For finding a stable basis - a point from where we could start our investigations - I rolled back qnice.c to the last point where my smoke test did not fail but work. @bernd-ulmann : Don't worry, none of your code changes since then is lost. :-) At least when we use the Git GUI that I use (SourceTree), there is a very convenient way to roll forward/backward, see differences, etc.
It did cost me quite some time (more than 1hr) just to find this last point of stable, so here is a wish, that I would like to share: Let's agree that any change to the semantics of any opcode any flag or any other ISA detail and (of course) the emulator automatically leads to someone of the three of us running the following smoke test right after the change was done:
cd emulator
rm qnice-vga
./run-vga.bash
<press enter>
<switch to the terminal screen and type> F R qbin/q-tris.out
Some important notes: rm qnice-vga
is necessary to force a rebuild when running ./run-vga.bash
. The latter one automatically downloads and mounts a FAT32 disk image.
And then: Play at least something like 60 seconds and clear one row, because funnily enough, one of the bugs that occured lead to not being able to clear any rows any more. Another one lead to the bricks just falling through. So just running Q-TRIS does not help. 60 seconds of gameplay are necessary and save hours of debugging later.
Here is what I found out (everything is related to our "ex branch" dev-io-addr
):
The last known good version is from August, 1st and the commit #8711d11
Commit #af2552a from August 7th is interessting: Q-TRIS still works, but FAT32 and/or SD Card do not
Status right now: Branch develop
is stable: Everything should work (hardware to be tested, because I was not able to), but all changes to the ISA and to the emulator in qnice.c
since August, 1st are rolled back (but not lost).
Enhance the simulation testbench of the timer interrupt hardware, including dev_int.asm
, so that the following daisy chaining edge case is tested:
Timer1 fires. Timer0 fires one (or very little) cycle(s) after timer1.
Expected behaviour: Timer1 is allowed to execute its interrupt. After that, timer0 executes its interrupt.
Changes to programming model:
The print character at VGA$CHAR will be extended to read/write a full 16-bit value instead of as today an 8-bit value. The lower 8 bits will remain the same as before, i.e. the ASCII character code. The upper 8 bits will be divided into two groups of 4 bits as follows:
The clear screen function will reset all characters to 0x20 (space) and will assign a default foreground and background colour to each character.
The cursor blink mode will swap foreground and background colour of the character.
Changes to VHDL code:
The video_bram module will have 16-bit data bus instead of 8-bit. This will double the amount of video RAM needed, going from 32 Block RAMs to 64 Block RAMs. Minor changes in vga_textmode.vhd. Most of the changes will be in the vga80x40.vhd module.
Changes to application code:
As written, all application code will break, because the value written to VGA$CHAR must now contain colour information as well in the upper 8 bits. One possible way to avoid this break, is to have different palettes for foreground and background. In other words, selecting both foreground and background colour as 0 would lead to the current behaviour of green on black.
Hello!
Could you please suggest which Xilinx FPGA I can use to implement this design for a UHS standard card?
Thank you!
In branch dev-int: There seems to be an emulator bug that prevents the timer from starting after a write/read register test:
I added a register write/read test to test_programs/timer_test.asm
: When running it at 0xE000
at first all registers are filled with some dummy values and then the dummy values are tested.
The write/read test itself passes, but after the successful write/read test, the timer interrupt's ISR is never called.
Maybe you have a look at issue #47 first, before diving back to work here ;-)
Info about the QNICE interrupt system is in the updated qnice_intro-pdf in branch dev-int, pages 9, 12 and the scheme and timing on pages 23-25.
The QNICE interrupt system is built as a Daisy chain. The more "left" (CPU being the leftmost device) you sit, the more priority you enjoy. This is why it felt very natural for me, to implement the two timers that are specified in sysdef.asm
as two Daisy chained timers, as you can see in branch dev-int
in the file timer_module.vhd
:
timer0 : timer
generic map
(
CLK_FREQ => CLK_FREQ,
IS_SIMULATION => IS_SIMULATION
)
port map
(
clk => clk,
reset => reset,
int_n_out => int_n_out, -- connect with "left" device (e.g. CPU)
grant_n_in => grant_n_in, -- ditto
int_n_in => '1', --t1_int_n_out, -- build Daisy Chain between timer0 and timer 1
grant_n_out => open, --t1_grant_n_in, -- ditto
en => t0_en,
we => t0_we,
reg => t0_reg,
data => data
);
As you can also see, I did comment out the Daisy chain signals of the second timer and instead, terminated the Daisy chain by applying a 1
to int_n_in
which translates to "there will never be any interrupt coming from "the right side" of the chain.
I did that, because otherwise, currently there is no bitstream written in branch dev-int
: Vivado complains about somethinig that I never heard before and I must admit the googling the term and looking at the forums did not really enlighten me, yet.
Do you have any insights in this phenomenon? What it is? Why it occurs here (did I make some bad mistake and I am just missing the obvious)? How to solve it?
So this is the reason, why right now, there is no Daisy chain and just timer0
while timer1
stays disabled.
If this does not ring a bell on your side - don't worry, then just assign this one back to me and I will continue to investigate.
This snippet from the emulator:
if (cmp_0 > cmp_1)
sr_bits |= 0x0020; // Set C-bit
else
sr_bits &= 0xfffb; // Clear C-bit
leaves me confused, because 0x0020
is not the inverse of 0xfffb
. This is comparing two signed numbers, so should that result be in the C bit or the N bit of the status register ?
One of the basic ideas of QNICE-FPGA is, that it is meant to be highly portable. For sure we are not there, yet ;-)
Currently, everything is quite Xilinx specific.
vhdl/hw
as well as the hw/xilinx
, hw/intel
folders might grow in future, making maintenance hard: Particularly due to duplicated and mainly identical files with slight platform specific changesIs there a way to work in VHDL a bit similar than with the C preproccessor? And then add some build system like CMAKE or the GNU build system?
E.g. in the source files as high level as #ifdef xilinx
and/or as low level as #ifdef enable_hdmi
and then something like
make nexys4
make MEGA65
make DE10
And the build environment is smart enough to grasp: OK, Nexys and MEGA65 are Xilinx, DE10 is intel...
Can we unite the zoo of vhdl files that right now have been doubled just because I did not know better how to do it? Like uniting MEGA65 globals and env1 globals. Uniting MEGA65_ISE.vhd
with MEGA65_Vivado.vhd
with env1 ISE and Vivado and so on.
Having some vhdl/hw/common
folder where all the common stuff resides and then the TRULY hardware specific stuff, such as HDMI and HyperRAM for MEGA65 then in a vhdl/MEGA65
folder.
uart.h and sysdef.asm have inconsistencies which should be resolved.
Add a register (IO memory address) that reads back the scan line currently being displayed.
Add a (same or separate?) register to store the value of a specific scan line.
Add registers to enable/disable interrupts when current scan line is equal to configured scan line.
This should probably be implemented AFTER Issue #17.
Enhance test_programs/cpu_test.asm
to be (nearly) complete.
Step 1: Do a bit more than today :-)
@bernd-ulmann The emulator seems to struggle either with post increments at software interrupts or with two software interrupts in a row (or with something else)
Switch to branch dev-int
and pull: I enhanced test_programs/int_test.asm
like this:
[...]
MOVE PREDECIND_1, R8 ; Test indirect ISR address with predecrement
INT @--R8
INT @R8++ ; test postincrement during INT
INT @R8
MOVE ITEST_3, R8
SYSCALL(puts, 1)
SYSCALL(exit, 1)
And while doing so, I also added an appropriate ISR to which @R8++
should point to and made sure that R8 is pushed on the stack during the PRE ISR, so that the correct R8 should still be available when doing the post increment.
The resulting output of the new test program should be:
QMON> CONTROL/RUN ADDRESS=8000
Start
ISR_ABS
ISR_REG
ISR_IND
ISR_PRE
ISR_PRE
ISR_POST
End
QMON>
But in fact, the last three outputs before End
are three ISR_PRE
in a row.
When disassembling code using the Monitor's built-in disassembler, relative addresses are shown as just that: relative.
I would like the disassembler to show the corresponding absolute address. For instance, the command "M S 0000 0060" currently shows:
0000 FFA0 RBRA 005A 1
...
005A FFA0 RBRA 0E88 1
005C 9FB8 AND 00FF R14
The instruction at 0000 jumps to address 005C. Showing the relative address (005A) makes the output harder to read.
This applies to the instructions RBRA and RSUB. The instructions ABRA and ASUB already show the absolute address. Alternatively, the relative instructions could show both the offset AND the absolute address, to make the distinction more clear.
Tentatively assigned to V1.7 if you agree.
Hey Michael, you for sure already now earned yourself a good spot in the QNICE hall of fame :-) So here is another small task for V1.6: Please add yourself to the README.md's Acknowledgements section: The one that is shown when you scroll down to the very end of the main README.md. Please do it in branch develop
.
Needs:
Gentlemen, I did it!! I merged dev-int
and dev-io-addr
into develop
this evening! ๐ฅณ ๐
There was astonishingly little trouble in the merging itself, because both of you were so disciplined, when committing to the different branches. So thank you very much for that!
That means we do not need the branches dev-int
and dev-io-addr
any more .
I am pretty sure, that we do not have merge errors, i.e. wrong versions or so. I double checked each file and when in doubt I used line-by-line merge and comparison tools such as Araxis Merge.
But I guess we all need to perform some smoke tests on develop
now - also and in particular, because I did all this work at a place, where I don't have an FPGA at hand, so all I could test was on the level of the emulator.
Michael, if you ever wanted to reproduce this cool "dual monitor" setup including a "jumping ball" on top of Q-TRIS on your own hardware: This might be the time, here is the comment that I mean:
BUT - as always, when so many changes have been done: Something broke. Not because of the merge! But because of the change in behaviour of the emulator. Since this has nothing todo with the merge itself, I opened a new issue for that called "Recent emulator changes broke SD Card, FAT32 and Q-TRIS". Let's use the new issue (issue #53) to discuss and work at that.
Let's use this issue at hand for all other smoke test results on the merging itself. I assume the merging itself worked pretty fine and we will be able to close this issue rather sooner than later. But I fear that issue #53 will be with us for a little longer.
There is a question to Michael about the old branches: So far, I never dared to delete any old branch due to the fear of loosing the history and due to the fact that I do not know how to do it right. Do you have experience with GitHub's behaviour about that in conjunction with the underlying Git? Bernd and I do not. So if you do: We might want to discuss also the deletion of old branches here in this issue before closing. Otherwise, let us just let them be for a little longer until we dare to proceed :-)
Gentlemen, this is an unusual "issue". It is just meant to share some joy with you about the first (still work-in-progress) version of the hardware timer interrupt in branch dev-int
: This branch now successfully runs test_programs/test_int.asm
(software interrupts) and test_programs/timer_test.asm
(hardware timer interrupts). But this is by far not all ;-) Read on!
IT IS SOOOOOO FREAKING AWESOME TO SEE. ๐
Here is what I did:
dev-int
and start it on the FPGAtest_programs/timer_test.asm
M
L
paste the timer test .out
into the terminal window and start it via C
R
E000
The output that then comes on serial is:
QMON> CONTROL/RUN ADDRESS=E000
Setup timer 0 to interrupt every 1000 milliseconds.
QMON> Timer 0 has issued interrupt request #0001
Timer 0 has issued interrupt request #0002
Timer 0 has issued interrupt request #0003
Timer 0 has issued interrupt request #0004
Timer 0 has issued interrupt request #0005
This is already pretty cool. But hang on, it gets cooler: Of course, the monitor is still working fine, as we are talking about real hardware timer interrupts. So even if the ISR spills our terminal window, the QMON>
prompt still works.
So - in my Nexys board, I have a FAT32 formatted SD Card, so I entered, while the ISR continues "spilling" and actually interrupting my while I type ๐ F
R
qbin/q-tris.out
as you can see here
Timer 0 has issued interrupt request #0013
Timer 0 has issued interrupt request #0014
FILE/Timer 0 has issued interrupt request #0015
RUN: qbTimer 0 has issued interrupt request #0016
in/q-tTimer 0 has issued interrupt request #0017
ris.outTimer 0 has issued interrupt request #0018
Timer 0 has issued interrupt request #0019
Successfully loaded qbin/q-tris.out from 8000 to 91E3
Running...
Timer 0 has issued interrupt request #001A
Timer 0 has issued interrupt request #001B
Timer 0 has issued interrupt request #001C
(The ISR sits above E000
and Q-TRIS loads to 8000
to 91E3
, so no overlap.)
And then - I can play Q-TRIS on the VGA screen, while on the terminal, it keeps counting. Slowly and steadily. Kind of a "multi monitor setup": VGA = Q-TRIS and UART = show ISR output. And of course you do not feel any disturbance because with our ~12 MIPS @ 50 MHz, QNICE is surely fast enough for that.
What a joy ๐
And then, in the end, the whole thing is deactivated by running C
R
E100
as seen here:
Timer 0 has issued interrupt request #007C
Timer 0 has issued interrupt request #007D
QMON> Timer 0 has issued interrupt request #007E
Timer 0 has issued interrupt request #007F
Timer 0 has issued interrupt request #0080
CONTROL/Timer 0 has issued interrupt request #0081
RUN ADDRESS=ETimer 0 has issued interrupt request #0082
100
QMON>
As soon as both of you have seen/read this - one of you can close the issue ;-)
Native toolchain assembler: Evaluate error after calling str2int
variables.asm: replace hardcoded blocksize for _SD$DEVICEHANDLE by using FAT32$DEV_STRUCT_SIZE
The latest stable release is V1.5. Currently, we have a ton of loose ends, so let us use this issue to define the scope of release 1.6 and track the progress towards release 1.6. Let's not start even more loose ends (such as removing the tristates everywhere) right now: We might soon open a second issue "Release 1.7: Scope" where we put all the stuff that takes longer.
develop
)Originally, I started release 1.6 with the goal to port QNICE-FPGA to the MEGA65. Before being able to do that, I needed to port it to Vivado first and before being able to do that, I needed to create the hw
folder including hw/README.md
where I did split the multiple FPGA hardware types and the build environment. Also the vhdl/hw
folder was created to host hardware specific code. When porting QNICE-FPGA to the MEGA65 I also improved a lot of documentation. And I made the whole toolchain Linux friendly.
Have a look at the work-in-progress VERSIONS.txt in the develop branch, it contains a rough "What has already been done" and what is still to be done list.
Here is the summary of what has already been done for V1.6 which is part of the develop
branch:
dev-int
)In branch dev-int
we are developing the QNICE interrupt system as it is described on pages 9, 12, 23-25 in this updated version of the intro document.
test_programs/int_test.asm
to test the software interrupts in all forms and shapes and test_programs/timer_test.asm
to test hardware interrupts using the timervhdl/sim
: Everything related with the development of the interrupt system is called dev_int*
: The asm
file is the test progrram, the dev_int.vhd
file is the top file for the simulation.timer_module.vhd
and timer.vhd
, particularly: Implement the correct Daisy Chaining mechanism and behaviour and rename the left
right
logic of the Daisy Chain in in
and out
dev-io-addr
)The goal is to have a more structured (and hardware implementation friendly) memory map. Issue #18 is tracking the progress.
monitor/sysdef.asm
keyboard.vhd
emulator/run_vga.bash
to support the new disk imageMake IO$GETCHAR smarter, so that switching STDIN does not require "one last keypress" on the old STDIN any more before reading from the new STDIN
The following snippet of code:
MOVE 0x0005, R1
MOVE 0x0007, R2
SUB R2, R1
calculates the subtraction 5-7 and gets the correct result -2 (represented as FFFE), but the overflow flag is set. In this calculation there is no overflow, and the overflow flag should be clear.
I assume the overflow flag should work just as on the 6502 processor. From the document http://www.righto.com/2012/12/the-6502-overflow-flag-explained.html I have extracted this excerpt:
The formulas for overflow during addition given earlier all work for subtraction, as long as the second argument (N) is ones-complemented. Since internall subtraction is just addition of the ones-complement, N can simply be replaced by 255-N in the formulas.
This could perhaps be used as part of the fix in the emulator.
The current design only stores the last pressed key. If the user presses multiple keys before the program reads from the keyboard device, then some key presses will be lost.
A small 32-byte FIFO just like the UART will take care of this.
Let's have consistent line endings in all VHDL files from version 1.6 on. But CAUTION: Let's do this change as one of the last changes we do, right before releasing. Reason: If we did it right now, we would have so many changes to soo many files that the process of merging dev-io-addr
plus dev-int
plus develop
plus master
would be a nightmare.
The reason why all these files are so scrambled, when it comes to line endings: I developed pre V1.6 with ISE under Windows. In V1.6 I switched to Vivado on Linux.
@MJoergen I guess Linux endings are fine, as all of us seem to run Vivado on Linux. I never did a "line ending change" in past and I assume you have some tool or something with which you could do that?
Part of release scope 1.6, issue #28
Branch to execute this on: develop
but only after dev-io-addr
and dev-int
are 100% done, tested and merged.
It might make sense to use IO$GETS_S
or a similar library function
While implementing the timer interrupt hardware I noticed, that during the "Interrupt Grant Phase" when the CPU's IGRANT_N
goes to 0
we need to de-couple all other devices from the DATA bus. Otherwise we might have a data clash on the bus.
Right now this logic is implemented in mmio_mux
by making sure that all the devices, including RAM and ROM and PORE are not enabled (i.e. the devices en = 0
and of course we = 0
).
I did not fully think through all edge cases.
For example what about the whole topic of cpu_wait_for_data
in mmio_mux
. On a first glance and thought, it looks innocent, but at least uart_cpu_ws
needs a second thought or in general the question: Will a disabled device automatically lead to correct behavuour in (a) all contexts and (b) in the particular context of cpu_wait_for_data
?
Are there more edge cases?
This topic has the potential for unpredictable crashes and nearly non-debuggable strange behaviour.
I ran into it when I tried to bring the hardware timer interrupt to life on real hardware. While in the simulation, everything worked like a charm, on hardware, literally nothing worked.
Therefore I plan to leave this issue open for a few releases and go forward like this:
For V1.6: When everything is merged to develop
and seems to work, rethink this and think about edge cases.
After releasing V1.6, do not close this but re-label it to V1.7
. Rethink the edge cases again, also in the context of the tristate-refatoring in issue #30 .
If possible for V1.7, write some timer interrupt stress test, that tries to provoke the edge cases, such as having timer activity while heavily working with the UART and it's uart_cpu_ws
and similar with RAM/ROM and it's wait-for-data equivalents
If all is good in V1.7, too, then we can think about closing this issue - or - pushing it forward one more release, just not to forget about it
EDIT 31.7.20, 21:57: Changed/Updated TODO LIST
Here are all steps necessary that came to my mind spontaneously. Please add your thoughts, maybe I forget something:
DONE BY SY2002 and VAXMAN Let's discuss the new Memory Map in monitor/sysdef.asm
here based on the assumption: The standard is 8 words for 8 registers per device, but we also allow devices to have 16 words. 256 words of MMIO space starting at FF00
.
DONE BY VAXMAN * There are some programs in test_programs
that still use hard-coded registers and the emulator also uses hardcoded register addresses: We need to sift through them and fix them.
DONE BY VAXMAN * The emulator should include ../dist_kit/sysdef.h
(**) instead of using hardcoded own #defines
to access registers
Recompile standard C library
Update MMIO hardware
Recompile all qbin files and update it in GitHub
DONE BY SY2002 Add MEGA65 MMIO to sysdef.asm and adjust MEGA65 samples and VHDL CODE
re (**) @MJoergen : FYI: The file monitor/sysdef.asm
is the single source of truth. There is a script called monitor/compile_and_distribute.sh
which is copying monitor/sysdef.asm
to dist_kit/sysdef.asm
and while doing so also generates a dist_kit/sysdef.h
for being used e.g. in the emulator but this dist_kit/sysdef.h
is also used in the implementation of the standard C library of QNICE that you find in c/qnice
(off-topic and by the way, a small intro how to use the C compiler is here: https://github.com/sy2002/QNICE-FPGA#programming-in-c)
Please fix in our interrupt dev branch dev-int
:
Correct typo in qnice_intro.pdf
On page #12, it states "All control instructions share the opcode D.".
I guess correct would be "E" instead of "D".
Add qtransfer as standard functionality to the Monitor
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.