Jump to content


  • Posts

  • Joined

  • Last visited

  • Days Won


Everything posted by Stefan

  1. Hi, Some pointers: Lose the .org and .segment statements, they are not needed The message string cannot be at the beginning of the source code if you intend to use $080d as entry point. The computer doesn't know if the bytes there are a string or code, it will try to run it as code, and the program likely crashes. Move the string to the end of the source. To compile I use the following command: cl65 -o HELLOWORLD.PRG -u __EXEHDR__ -t cx16 -C cx16-asm.cfg helloworld.asm The compiler translates ASCII to PETSCII correctly, but note that an unshifted char in your modern PC will be an uppercase char on the X16, presuming you are using the default uppercase/graphics mode that the X16 is started in. The modified source code that I tested (lines that could be removed commented out): ;.org $080D ;.segment "STARTUP" ;.segment "INIT" ;.segment "ONCE" .segment "CODE" CHROUT = $FFD2 ;CHRIN = $FFCF ZP_PTR_0 = $20 start: lda #<message sta ZP_PTR_0 lda #>message sta ZP_PTR_0 + 1 ldy #0 @loop: lda (ZP_PTR_0),y beq stop JSR CHROUT iny bra @loop stop: rts message: .byte "hello",0
  2. I made a separate thread about the SD card issues, should anyone want to continue this discussion.
  3. There was some discussion in the above thread about the SD card not always being recognized by the last development board. It's a good idea to move that discussion to a separate thread, should anyone want to continue. The simplified SD card spec may be downloaded here: https://www.sdcard.org/downloads/pls/pdf/?p=Part1_Physical_Layer_Simplified_Specification_Ver8.00.jpg&f=Part1_Physical_Layer_Simplified_Specification_Ver8.00.pdf&e=EN_SS1_8 As @Wavicle said, it follows from section 4.4 that the host is not required to keep a continuous clock frequency. The clock may even be stopped for instance while the host is filling its output buffer. However, the specification also talks about exemptions to this, for example during the ACMD41 command (card initialization). I don't know if the exemptions are relevant, but they might be. Anyway, if the SD card during the initialization command requires a continuous clock frequency in the range 100-400 kHz, and if the initialization request/response, as I understand the code in dos/fat32/sdcard.s:232-301, consists of multiple bytes, the X16 running at 2 MHz will not be able to keep up at 100 kHz. I have no intention to look any further at this question myself, at least not for now. I think the right way to proceed, is to make the PS/2 keyboard work at 8 MHz, and thereafter look at the SD card issue if it doesn't work reliably when the computer runs at 8 MHz.
  4. Even though there is no timing dependent code in those lines, there is in other places within the module, for instance: wait_ready, begins at line 40 sdcard_init, begins at line 236 I haven't gone into the details of the SD card protocol. I haven't analyzed if the changed timing when the clock rate is reduced would be OK. I only said that the Kernal code clearly is written on the assumption that the computer runs at 8 MHz, and that it would be interesting to know if the problem is still there when the computer is run at that speed. EDIT: Let me be clear about that I have no practical experience interfacing SD cards. Reading about the protocol in datasheets, I understand that there is no minimum clock frequency during normal communication. But during card initialization, you may not go below 100 kHz. When X16 is run at 2 MHz, 100 kHz corresponds to 20 processor cycles. It so happens that the spi_read function that is called several times during card initialization is a little more than 20 cycles. As I said, it would be interesting to know how well SD card communication works at 8 MHz...
  5. I also looked briefly at the code that handles SD card communication (dos/fat32/sdcard.s). It's a bit banged SPI solution that depends on proper timing. The necessary timing delays are measured in processor cycles, calculated on the assumption that the X16 runs at 8 MHz. It would be surprising if the code worked properly if you run the computer at 4 or 2 MHz. Before any other troubleshooting, it would be interesting to know how well the SD card communication works at 8 MHz. To test this you may first need the keyboard to work at that speed
  6. If the first attempt is not successful, you may try this that prolongs the initial wait for the keyboard from about 108 us to over 400 us. This also works in the emulator. ps2.s rom.bin
  7. @Kevin Williams I made a quick test introducing a wait of about 15 us after clock low transition before the data line is sampled. At least that was my intention, but I have no means of testing it. It still works in the emulator. Enclosed is the changed source file (kernal/drivers/x16/ps2.s and the compiled rom image. The changes in the source file is on line 69 and on lines 105 and forward. ps2.s rom.bin
  8. I looked around a bit for trustworthy information on PS/2 timing. I found this 1991 IBM manual titled "Keyboard and Auxiliary Device Controller" page 16 (page 230 in the file). https://archive.org/details/bitsavers_ibmpcps284erfaceTechnicalReferenceCommonInterfaces_39004874/page/n229/mode/2up?q=keyboard Possible timing problems: The time it takes after PS/2 lines are released by the host before the keyboard starts sending data. The current X16 Kernal waits about 108 us @ 8 MHz according to my manual clock counting. I have found no documentation stating when the keyboard must start sending data, only that it cannot begin before 50 us after the PS/2 lines were released. It would be interesting to see what happens if the time the Kernal is waiting for the keyboard to start sending data is made longer. The current Kernal samples the data line immediately after the clock goes low. This should be fine according to the specification, if the keyboard in question follows the specification. It would, however, be interesting to see what happens if the data data line is sampled in the middle of the clock low period, for example about 15-20 us after the clock transition.
  9. I believe this to be very true. Switching RAM bank in X16 is the time it takes to write a value to a zero page address, i.e. 3 clock cycles = 375 ns @ 8MHz. Virtual RAM bank switching would require you to first write the current bank values to disk (8 kB) and then read the new bank values from disk (also 8 kB). In this thread, @Michael Steil commented the theoretical max throughput of the file system - about 13 kB/s if using (the KERNAL's) byte by byte operations, or 140 kB using the DOS routine macptr (I haven't looked closely on that, but it sounds interesting as the programs I've made have a throughput close to 13 kB/s). https://www.commanderx16.com/forum/index.php?/topic/346-how-fast-will-sd-card-access-be-on-hardware/#comment-2223 Let's assume you would actually achieve both a read and write speed of 140 kB/s. First writing, and then reading 8 kB would take like 0,11 seconds. At 13 kB/s it would take about 1.23 seconds, by the way. 0.11 seconds is quick, but compared to X16 bank switching it's very slow. In fact, you could make about 293,000 X16 bank switches in the time it takes to do one virtual disk based bank switch (assuming read/write speed of 140 kB/s). This doesn't mean that the X8 is useless. It means that the X8 and X16 requires fundamentally different thinking when you make programs. And some programs that need to use banked RAM a lot will be virtually impossible to port from X16 to X8. I would certainly miss the real banked RAM of X16 if this project ended up being the X8 (only). The banked RAM is what opens so many opportunities for interesting 8 bit programming.
  10. If doing code for both X16 and X8, I would for performance reasons first look into creating a set of macros rather than using a common API. As to bank switching, such a macro could on the X16 just select the RAM bank. On the X8 that macro could load a virtual memory file (for instance numbered 0-255) into memory area $a000-$bfff. However, first the current content of $a000-$bfff need to be saved to its virtual memory file. Maybe similar solutions are available for VERA access. I haven't given that much thought yet.
  11. Some thoughts on porting a X16 assembly program to X8. The time and effort it takes will vary a lot depending on the structure of the program. Especially programs depending on banked RAM will be hard, as it's just not just a different interface, but an important feature that is missing entirely. Taking X16 Edit as an example, you would probably need to replace banked RAM with virtual memory on disk. This would require a complete rewrite of large parts of the program. At present X16 Edit does bank switching in 67 different situations. Virtual memory banks would not be a simple drop in. You would need to find new strategies to avoid unnecessary reading and writing from/to the disk. It think it would be a lot of work, almost easier to start from scratch. The different VERA interface might be easier to handle. In X16 Edit the VERA_D0 register is read or written in 33 different situations, so porting this to X8 is not trivial. I do not believe in hiding the differences between X16 and X8 behind API layers. 8 bit computers running at 8 or 12 MHz need all computational power they have if we are to make great programs. Even if there were such an API many assembly programmers would avoid it to gain performance. If the X16 and X8 are incompatible, the programs written for them will be so too. If both the X8 and the X16 are released, developer time will be divided between the two platforms.
  12. Keeping up the spirit, I just finished a RPi Zero W "hat" that can be used to connect to the X16 over I2C. It was less than 2 € for 5 pcs + postage, so I also ordered the part.
  13. I think it's great that David so openly shared this information with the community. We could feel that there were hurdles, but it's better to have first hand information. If money is no object, I'm personally most interested in the phase 1, whether in kit form or pre-assembled. Converting assembly programs from X16 to X8 may very well prove to be a hassle. The differences, as described, seem to be quite substantial: no banked RAM, less VRAM and different access logic to VERA. It feels like X16 and X8 are no more related than cousins, like VIC20 and C64 for instance. A X16 program could be ported to X8 but would take some effort and the result would in many cases be restricted in some ways. Attracting developers and building a sufficient software library might be the most demanding aspect of successfully launching a new computer platform. Therefore you need to think carefully before dividing the developer efforts between two platforms.
  14. As I now might have the basis for a transport layer over I2C I'm thinking about a communication protocol. So far this is what I have in mind. X16 to RPi requests The first data byte sent would select a command to be executed on the RPi The rest of the data sent would be command specific A command that invokes the Linux program lp to print a file could be formatted as follows: A null terminated string containing the command line params to be given lp Then the content to be printed as a stream of characters/bytes A command that invokes curl to fetch a web resource could contain the following: A null terminated string containing the params to curl RPi to X16 responses Reading from the RPi would always return the response of the last command. The response could be formatted as follows: One byte: Response code (interpretation command specific) Three bytes: Length of response stream (three bytes addresses more than a fully expanded X16) The actual response stream Please let me know if you see problems or better ways of doing this.
  15. I've made some small progress. I have managed to setup a Raspberry Pi Zero W as I2C slave and a Ardunio Uno as I2C master: Electrical connections The Arduino is powered by USB The RPi is powered from the Arduino 5V pin to RPi pin 2 (5V) The Arduino ground is connected to RPi pin 6 (GND), ensuring a common ground I have a voltage level converter (5V/3.3V). This is driven by the 5V and 3.3 V outputs of the Arduino. Arduino pin A4 (SDA) is connected to the voltage level converter 5V side. The low voltage side is connected to RPi pin 12 (GPIO 18) Arduino pin A5 (CLC) is connected to the voltage level converter 5V side. The low voltage side is connected to RPi pin 35 (GPIO 19) The Arduino runs a program that sends the text "Hello world" once every second to I2C slave address 4 The RPi runs a loop that listens on that slave address and prints incoming text to the terminal Arduino code #include <Wire.h> void setup() { // put your setup code here, to run once: Wire.begin(); } void loop() { // put your main code here, to run repeatedly: Wire.beginTransmission(4); Wire.write("Hello world"); Wire.endTransmission(); delay(1000); } RPi code The code I used on the RPi is basically identical to the example/instruction published here: https://raspberrypi.stackexchange.com/questions/76109/raspberry-as-an-i2c-slave Attached is a short video showing this contraption running. Not Ben Eater quality, I'm afraid But hopefully you get the idea. IMG_0228.MOV
  16. Thanks @Lorin Millsap! I looked at and calculated the wait loop on lines 55-60 in the file x16-rom/kernal/drivers/x16/ps2.s (Github master branch) once more. AFAIU: The loop setup on lines 55-56 is 4 cycles. The loop counter (Y) is set to 80. Each loop (lines 57-60) takes 11 cycles. The test for a start condition happens 4 cycles into the loop. The loop will check for a start condition 79 times The last check will happen 4 + 78*11 + 4 = 866 cycles after the I2C lines were released 866 cycles @ 8 MHz processor speed is about 108 us. @ 2 MHz it's about 433 us. If the keyboard hasn't started to transfer data within that time, the PS/2 lines are made inactive again. As far as I can see, there are no other parts of the Kernal PS/2 code that has a similar timeout. If receiving a start condition, the code will wait (indefinitely) for the keyboard to finish transmission. Instead of lowering the processor speed, you could increase the value of the loop counter on line 56. If the counter is set to it's maximum value of 255, the timeout will happen after 349 us. If that's not enough, you could add one ore more NOPs to the loop for testing purposes. One NOP at the beginning of the loop would increase the wait to about 414 us if the loop counter is set to 255.
  17. I remember @Lorin Millsap said some months ago, that the current Kernal function for reading the keyboard would not be the one to be used in the final product. On Github, there is the "ps2-nmi" branch last updated at the end of April. I haven't analyzed the code, but it seems to be an interrupt based solution instead of the polling method used in the current master branch.
  18. David made an interesting update on Youtube today. Apparently there is some kind of timing issue when reading the keyboard. It works reliably only when the board is operating av 2 MHz. David said it was probably "software" related, i.e. the Kernal's PS/2 driver. AFAIA, the Kernal holds the PS/2 clock and data lines inactive most of the time. When it's ready to receive data from the keyboard, the lines are released, and (I suppose) pulled high by a pull-up on the VIA pins. The Kernal then polls the state of the PS/2 lines for about 100 us. If the keyboard has not begun sending data within that period of time, the Kernal pulls the clock and data lines to the inactive state again, and continues with other chores. The PS/2 protocol gives devices some leeway when it comes to timing. I haven't found any specification on how fast a device must start sending data after the clock and data lines are released by the host. It is only said that communication may not start before 50 us after the lines were released. It is possible to let the Kernal wait longer for the keyboard to start sending data. The drawback is, of coarse, that this holds up the whole system. The current waiting period of about 100 us is 0.6 % of the vertical blank at 60 Hz. Multiplying the waiting time by four (corresponding to the transition from 8 MHz to 2 MHz) would make it 2.4 % of the vertical blank. That is still OK. To test if this actually solves the problem, you would only need to change the value "10" on line 56 in the file x16-rom/kernal/drivers/x16/ps2.s (Github master branch). I look forward to follow the crew solving these last gremlins.
  19. I guess we all agree with @TomXP411 on how the cursor should work. Still in R39, when you hold down a key, the cursor is mostly hidden. Maybe not a big problem, but it doesn't look good. Some other things I've observed if you were to build the perfect cursor: In ISO mode there are no inverted characters. When the cursor is turned on standing over a character you cannot see what's behind it in R38/R39 when in ISO mode. Not a big problem as you can see the character during the period when the cursor is off, but still not perfect. If in 16 color text mode, you could make a cursor that swaps the background and foreground colors instead of changing the character. That looks the same as inverted characters in PETSCII mode, and it would work in both PETSCII and ISO mode. In the X16 Edit R39 version I'm using this technique, and it works very well. However, in 256 color text mode, you cannot change the background color of individual characters. The color swap method would not work The only method I can think of that would work in ISO mode + 256 color text mode is to use a sprite The sprite would be just a filled box in the foreground color of the same size as a character (the same as an inverted blank space that is) The Z-depth of the cursor sprite would be behind layer 0 and 1 but in front of the background When the cursor is turned on, the sprite is made visible at the right position and the character color is changed to the background color of the screen It should look like an inverted character, but I haven't actually tested it The drawback is that you are using one sprite To cover all modes you would need at least two alternative cursor functions One using the color swap method when in 16 color mode One using the sprite method when in 256 color mode
  20. Hi Philip, Have you thought about making your own cursor from scratch? It's not that hard to do, and you are not relying on Kernal code subject to change. /Stefan.
  21. Some thoughts on X16 <-> RPi communication As far as I can tell, the X16 Kernal is bit banging the I2C protocol. I do not know what speed we are to except. Furthermore, I assume from skimming over the X16 Kernal source code that it will only work in I2C master mode Making the RPi act as an I2C slave might not be straightforward, but there seems to be a hardware supported slave mode I found this discussion thread on using the RPi as a slave Link: https://raspberrypi.stackexchange.com/questions/76109/raspberry-as-an-i2c-slave According to this, you must use GPIO 18 and 19 in slave mode (not the same pins as in master mode) My old RPi (actually the first version ever launched) does not expose those two pins. I need to buy a newer RPi. I have ordered a RPi zero W, which I understand has both GPIO 18 and 19 linked to the header. If anyone of you have practical experience on how to set up an RPi as an I2C slave, please share. If it's possible to make this work, that opens a lot of possibilities beyond printing: You could get access to the Internet over the RPi (even over WiFi) You could use the RPi to store files (may not be very interesting, an SD card holds a lot of data) You could communicate with other USB devices than printers My plan is to build a test rig with an Arduino as I2C master and RPi Zero W as slave. The Arduino has good I2C support and is mostly using 5V levels as the X16, so I can test that the voltage level converters I have at home are good (fast) enough for this application.
  22. I continued on making a PostScript template that could be used as the basis for a printing solution. After some initial hurdles, I come to like PostScript a lot. The template is attached. Some remarks: There are some variables you may set in the header pagh = page height pagw = page width lmarg = left margin bmarg = bottom margin tmarg = top margin rmarg = right margin leading = line spacing All of those in points, 1 inch = 72 points Custom procedures defined in the header normal = select default font, in the template that's Courier 10 pt NP = Create new page NL = New line PR = Print text string (one or many lines) The template supports printing with Latin1 encoding I have written this template mostly with the needs of X16 Edit in mind. I could make X16 Edit output the PostScript header quite easily. The header could be condensed by removing comments and white space. It should then be less than 1 kB. You then need to continue to output the actual content to be printed. Enclose each line of text to be printed in parenthesis. That's the way PostScript marks strings, not using quotes as most programming languages Thereafter call PR to print and NL to insert a line break After all text has been outputted you lastly need to call the showpage function The actual printing part would not contain a lot of overhead. It would look something like this. (Hello world) PR NL (Another hello) PR showpage My next step is to fire up my old RPi and see what I can do with that. Can I configure it as a I2C slave and make it print a PostScript file transferred to it? I cannot say I have a lot of experience, but learning to do something new is half the fun. template.ps
  23. I've never looked closely on PostScript before, and I find it demanding but quite interesting. I think a PostScript based printing solution would work very well. As you may know, PostScript is just plain ASCII text which a X16 program could generate easily, send it to an RPi based printer adapter over I2C, which would send it to the actual printer. My initial attempt to write a PostScript "program" that handles line and page wrapping by itself is enclosed. I printed it with Ghostscript on MacOS to a PDF file with the following command: gs -sDEVICE=pdfwrite -o test.pdf test.ps test.ps
  24. That function is only supported in the Kernal master branch on Github, what is expected to become R39. BTW: I'm using a custom key handler in the X16 Edit pre-R39 version. It adds support for the END and DELETE keys and also the numerical keypad keys. That works very well, I would say. As you may see, the key handler is similar to a custom interrupt handler.
  25. The ESC/P (Epson) printer protocol is interesting for historical reasons, and supporting it might also make it easier to port programs made for other 8 bit platforms. It is, however, quite closely tied to functioning of dot matrix printers. Not everything makes sense on a laser printer, and you are also loosing some possibilities supported by a laser printer. I guess that's why Postscript was invented in the first place. If I was to design a printer solution, I would like to keep the options open, supporting more than one printing protocol/format, and making it expandable. To print an ESC/P byte stream, you would need to find or create a program that runs on the RPi and that converts the ESC/P input to Postscript or PDF. Making this from scratch is not an easy task. There are some open source alternatives available that I haven't yet tried. An example is found here: https://github.com/RWAP/PrinterToPDF/. If there is a ready-made conversion tool, implementing support for ESC/P would be very doable. Postscript input is easy to print from the RPi. But making your X16 program output raw Postscript might be too big of a challenge for most programmers. Having your X16 program outputting TeX or LaTeX is a lot easier than Postscript, and that has the benefit over ESC/P that you could use all features supported by a modern laser printer. And there are of coarse a multitude of other markup languages that could be used as the basis of a printing system.
  • Create New...

Important Information

Please review our Terms of Use