-
New Assembly & Demo Video from "Mein Elektronik Hobby"!
08/21/2024 at 01:18 • 0 comments -
RetroChallenge 2023/10 Grand Prize for PicoRAM 2090
08/11/2024 at 00:00 • 2 commentsPicoRAM 2090 won the "Grand Prize" in the RetroChallenge 2023/10!
Thanks much, guys - it's the project that I am most proud of, and I feel very honored that it got recognized with the renown and reputable "RetroChallenge Grand Prize Winner" label. After all, the RetroChallenge gave us fantastic retro computer projects such as the RC2014.
-
Firmware Source Committed
12/12/2023 at 02:47 • 0 commentshttps://github.com/lambdamikel/picoram2090/tree/main/src/picoram_2090
I am omitting the TTS code for now though (i.e., the SPI Interface to the Epson S1V30120). -
PicoRAM 2090 got a link on the official Busch homepage!
12/05/2023 at 02:43 • 0 comments -
Final Demo Video: https://youtu.be/dFnKhUI47KU
11/26/2023 at 18:30 • 0 commentsIt's the end of the project as we know it - thanks for hanging on, folks!
-
GitHub updated! https://github.com/lambdamikel/picoram2090
11/25/2023 at 17:44 • 0 commentsThe GitHub repo and page have been updated. The repo also includes the Gerbers and firmware by now; firmware sources will come a bit later as I am still refactoring things a bit:
https://github.com/lambdamikel/picoram2090
Enjoy!
-
Final PicoRAM 2090 PCB
11/24/2023 at 05:15 • 0 commentsThe third revision of the PCB is the final one for now - I have fixed all shortcomings and am satisfied with it for now. Now, I'll make one more final demo video, and then upload of the sources and Gerbers to GitHub.
-
First PCB Assembled
11/19/2023 at 16:50 • 0 commentsThe good news is - it works!
The bad news is: I'll need one more round of PCB revisions; problems are:
- the power switch is blocking the Pico's USB port - I hence had to put in a temporary micro slide switch which is very flimsy and a bit of a hack.
- I also learned that the double throw 6pin DPDT power blue & white switches come in 7x7 and 8x8 mm; the 7x7 that I currently have don't fit the KiCAD footprints without pin bending. So I ordered the 8x8 ones.
- the silkscreen text for buttons and button legend is too small.
- the SRAM 2114 data lines are in reverse bit order - I had to change the firmware for now by including a reverse_bits on the data lines, but have fixed this already in the PCB.
- the voltage divider for the Microtronic's DISP line is 1k-1k instead of 1k-2k... I had to cut a trace and use one of the spare 2k resistors in one of the isolated resistor network DIPs with a bodge wire.
- I made a stupid mistake when I crimped the 2114 connector cable - it took me 2 hours before I finally identified the badly crimped cable shorting every adjacent pair of wires, questioning my design, as the main culprit why it wouldn't work at all at first. I had to de-solder the crimp connector from the board and messed up a trace, requiring one more bodge wire.
Well, the 2nd revision of the PCB is already in production, and this should be the final one!
Here are a few pics of the mess ups:
-
PCB Designed and in Production!
11/12/2023 at 16:19 • 0 commentsWaiting for the PCB to arrive...
-
RetroChallenge 2023/10 Log Entry #6 - Final Wrap-Up Demo Video
10/29/2023 at 07:48 • 0 commentsI achieved everything I wanted for this year's RetroChallenge 2023/10 - here is a final wrap up demo video:
So the last week I mostly spent time writing the demo programs you see in the video. Some of these graphics demos (involving trig) were created with the help of a bunch of little Lisp functions (see below) - the Microtronic cannot do trig functions (sin, cos) reasonably fast, so these were pre-computed with Lisp and materialized in the code. The Lisp-program generated Microtronic instructions were just put in a .MIC file and then put on the PicoRAM's SD card. In the end, it turned out to be a good design decision to utilize an SD card interface for memory dumps / .MIC file storage, as opposed to, say, an EEPROM - given that I can easily create and exchange .MIC programs / content with and from the PC using the SD card.
It might be a good idea to actually add extended op-codes just for trig, i.e., if I wanted to add simple Logo-turtle like graphics capabilities as op-codes, I will need fast trig from register memory as well. For now, I've run out of available vacuous op-codes, but it is of course possible to implement different sets of vacuous op-codes. There could be one set which includes op-codes for sound and speech, like the current set, and another set that utilizes the same vacuous op-codes for trig functions instead. I could use one of the PicoRAM push buttons to cycle through different op-code sets, just like I am doing now to swap memory banks.
Interesting side note: running some of these graphics demos, I noticed that the 2nd core, which is running the op-code extensions, display, user interface, SD card interface, speech, sound, .etc., wasn't fast enough during certain display line drawing operations to keep up with the Microtronic. As the PicoRAM has no way of halting the Microtronic (it only snoops the RAM bus!), if the extended op-codes such as drawing a line to the display take too long, the 2nd core might miss the next extended op-code if it's still busy executing the current operation (e.g., drawing the line). Hence resulting in (graphics) glitches.
Solution: I overclocked the Pico to 250 Mhz - all glitches are gone! This problem never occurred for the SRAM emulation running on the 1st core, only the 2nd core was problematic as it was implementing the extended op-codes, driving the display, etc. In general, the Pico is a great platform for this kind of work - fast and powerful. I don't think this would have been possible with the old AVR MCUs - the 2nd core is a blessing. And overclocking and using the 2nd core is insanely easy, even from C! It's definitely a platform / MCU I am going to use for future projects. Despite the slight annoying required level shifters, it's close to perfect.
Speaking of the op-codes - writing all these demo programs I tweaked the firmware and its op-codes here and there, just to make the programming more convenient. You don't really know how well a programming language or a set of op-codes works until you eat your own dog food! For example, I removed the original
50D SOUND PLAY FREQ <X><Y>
op-codes because I found it more useful to have an op-code that enables auto-echo to the speech synthesizer of text. With speech echo enabled, I can use the
506 DISP SHOW CHAR <LOW><HIGH>
op-code to drive the text display as well as the speech synthesizer.
The final (hah - or let's say latest, current) set of op-codes is hence the following:
0xx ENTER LITERAL DATA x 3Fx ENTER DATA FROM REG x 500 HEX DATA ENTRY MODE 501 DEC DATA ENTRY MODE 502 DISP CLEAR SCREEN 503 DISP TOGGLE UPDATE 504 DISP REFRESH 505 DISP CLEAR LINE 506 DISP SHOW CHAR 507 DISP CURSOR SET CURSOR LINE 508 DISP SET CURSOR 509 DISP PLOT 50A DISP LINE 50B DISP LINE FROM 50C DISP LINE TO 50D SOUND PLAY NOTE (SOUND OFF FIRST) 50E SPEAK DISP ECHO 50F SPEAK BYTE 70x SWITCH MEMORY BANK x
And here is the Lisp program that I used to generate some of these demo programs:
(in-package :cl-user) (defun sin-d (x) (sin (* (/ x 180) pi))) (defun cos-d (x) (cos (* (/ x 180) pi))) (defun invert (x) (let ((string (format nil "~2,'0X" x))) (format nil "~A~A" (elt string 1) (elt string 0)))) (defvar *adr* 0) (defun low-nibble (x) (let ((string (format nil "~2,'0X" x))) (format t "~2,'0X 0~A~A~%" (incf *adr*) (elt string 1) (elt string 1)))) (defun high-nibble (x) (let ((string (format nil "~2,'0X" x))) (format t "~2,'0X 0~A~A~%" (incf *adr*) (elt string 0) (elt string 0)))) (defun low-nibble0 (x) (let ((string (format nil "~2,'0X" x))) (format t "0~A~A~%" (elt string 1) (elt string 1)))) (defun high-nibble0 (x) (let ((string (format nil "~2,'0X" x))) (format t "0~A~A~%" (elt string 0) (elt string 0)))) (defun test (n) ;; polygon k-m (setf *adr* 0) (loop as a from 0 by (/ 360 n) do (when (>= a 360) (return)) (format t "~2,'0X F10~%" *adr*) (format t "~2,'0X 509~%" (incf *adr*)) (low-nibble (round (+ #x40 (* #x3f (cos-d a))))) (high-nibble (round (+ #x40 (* #x3f (cos-d a))))) (low-nibble (round (+ #x10 (* #x0f (sin-d a))))) (high-nibble (round (+ #x10 (* #x0f (sin-d a))))) (format t "~2,'0X 50B~%" (incf *adr*)) (loop as b from 0 by (/ 360 n) do (when (>= b 360) (return)) (low-nibble (round (+ #x40 (* #x3f (cos-d b))))) (high-nibble (round (+ #x40 (* #x3f (cos-d b))))) (low-nibble (round (+ #x10 (* #x0f (sin-d b))))) (high-nibble (round (+ #x10 (* #x0f (sin-d b)))))))) (defun test2 (n) ;; circle granularity n (let ((rx #x3f) (ry #x0f)) (format t "F10~%") (format t "509~%") (loop as a from 0 by (/ 360 n) do (when (> a (+ 360 (/ 360 n))) (return)) (low-nibble0 (round (+ #x40 (* rx (cos-d a))))) (high-nibble0 (round (+ #x40 (* rx (cos-d a))))) (low-nibble0 (round (+ #x10 (* ry (sin-d a))))) (high-nibble0 (round (+ #x10 (* ry (sin-d a))))) (when (> a 0) (format t "50C~%"))) (format t "F00~%"))) (defun test3 (n m) ;; with sound! and nested circles ;; not good... (let* ((rx #x3f) (ry #x0f) (ix (round (/ rx m))) (iy (round (/ ry m)))) (format t "F10~%") (dotimes (i m) (loop as a from 0 by (/ 360 n) as step from 0 by 1 do (format t "50D~%") (low-nibble0 i) (low-nibble0 step) (format t "509~%") (when (> a (+ 360 (/ 360 n))) (return)) (low-nibble0 (round (+ #x40 (* rx (cos-d a))))) (high-nibble0 (round (+ #x40 (* rx (cos-d a))))) (low-nibble0 (round (+ #x10 (* ry (sin-d a))))) (high-nibble0 (round (+ #x10 (* ry (sin-d a))))) (when (> a 0) (format t "50C~%"))) (decf rx ix) (decf ry iy)) (format t "502~%") (format t "C00~%"))) (defun test3a (n m) ;; with sound! and nested circles (let* ((rx #x3f) (ry #x0f) (ix (round (/ rx m))) (iy (round (/ ry m)))) (format t "F10~%") (dotimes (i m) (format t "50D~%") (low-nibble0 1) (low-nibble0 i) (format t "509~%") (loop as a from 0 by (/ 360 n) as step from 0 by 1 do (when (> a (+ 360 (/ 360 n))) (return)) (low-nibble0 (round (+ #x40 (* rx (cos-d a))))) (high-nibble0 (round (+ #x40 (* rx (cos-d a))))) (low-nibble0 (round (+ #x10 (* ry (sin-d a))))) (high-nibble0 (round (+ #x10 (* ry (sin-d a))))) (when (> a 0) (format t "50C~%"))) (decf rx ix) (decf ry iy)) (format t "502~%") (format t "C00~%"))) (defun test4 (n m) ;; nested circles animation (let* ((rx #x3f) (ry #x0f) (ix (round (/ rx m))) (iy (round (/ ry m)))) (format t "F10~%") (format t "503~%") (dotimes (i m) (format t "509~%") (loop as a from 0 by (/ 360 n) do (when (> a (+ 360 (/ 360 n))) (return)) (low-nibble0 (round (+ #x40 (* rx (cos-d a))))) (high-nibble0 (round (+ #x40 (* rx (cos-d a))))) (low-nibble0 (round (+ #x10 (* ry (sin-d a))))) (high-nibble0 (round (+ #x10 (* ry (sin-d a))))) (when (> a 0) (format t "50C~%"))) (format t "504~%") (decf rx ix) (decf ry iy)) (format t "502~%") (format t "503~%") (format t "C00~%"))) (defun test5 (n m step) ;; nested circle animation with step rotation for each (let* ((rx #x3f) (ry #x0f) (ix (round (/ rx m))) (iy (round (/ ry m))) (aoff 0)) (format t "F10~%") (format t "503~%") (dotimes (i m) (format t "509~%") (loop as a from 0 by (/ 360 n) do (when (> a (+ 360 (/ 360 n))) (return)) (let ((a (+ a aoff))) (low-nibble0 (round (+ #x40 (* rx (cos-d a))))) (high-nibble0 (round (+ #x40 (* rx (cos-d a))))) (low-nibble0 (round (+ #x10 (* ry (sin-d a))))) (high-nibble0 (round (+ #x10 (* ry (sin-d a)))))) (when (> a 0) (format t "50C~%"))) (format t "504~%") (decf rx ix) (decf ry iy) (incf aoff step)) (format t "502~%") (format t "503~%") (format t "C00~%"))) (defun string-to-ascii (string file) (format file "F10") (format file "~%502") (format file "~%50E") (format file "~%506") (dolist (x ;;(substitute #\Space #\Newline (coerce string 'list))) (remove #\Newline (coerce string 'list))) (let ((string (string-upcase (format nil "~2,'0X" (char-code x))))) (format file "~%0~A~A" (elt string 1) (elt string 1)) (format file "~%0~A~A" (elt string 0) (elt string 0))))) (defun page-bank-reader (pages) (let ((bank 0)) (dolist (page pages) (with-open-file (file (format nil "c:/temp/PAGE~A.MIC" bank) :direction :output :if-exists :supersede) (string-to-ascii page file) (incf bank) (format file "~%50F") (format file "~%0AA") (format file "~%000") (format file "~%FF0") (format file "~%70~X" bank) (format file "~%C00~%~%"))))) (page-bank-reader (list "Hi. Nice to meet you. I am the Microtronic 2090 Computer System." "I was created in 1981 by the ELO magazine and the company Busch." "My CPU is a 4bit T M S 1600 micro controller. And I have a RAM of" "256 12bit words. I speak a custom machine language and I am big in" "education. With my PicoRAM I can now do things that ought to be" "impossible for me. My master LambaMikel loves me. Bye bye now.")) (defun spiral (n m ) ;; draw a spiral (let* ((rx #x3f) (ry #x0f) (irx (/ rx (* n m))) (iry (/ ry (* n m)))) (format t "F10~%") (format t "509~%") (loop as a from 0 by (/ 360 n) as step from 1 to (* n m) do (low-nibble0 (round (+ #x40 (* (round rx) (cos-d a))))) (high-nibble0 (round (+ #x40 (* (round rx) (cos-d a))))) (low-nibble0 (round (+ #x10 (* (round ry) (sin-d a))))) (high-nibble0 (round (+ #x10 (* (round ry) (sin-d a))))) (when (> a 0) (format t "50C~%")) (decf rx irx) (decf ry iry)) (format t "502~%") (format t "C00~%")))