Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    emard
    @emard
    I don't know if that is possible but like to have possibility for nmigenator (like verilator), the interpreter that will only from given nmigen code produce signals, skipping translation to verilog. It can then allow introspection using python to use hi-level language to track down bugs
    Lawrie Griffiths
    @lawrie
    Another interesting project written in nmigen, which now runs on the Ulx3s is Luna - https://github.com/greatscottgadgets/luna
    emard
    @emard
    Yes this project is great! I think LUNA should already have ulx3s board, Goran told me something. For USB sniffing, here's shopping lists in the manual https://github.com/emard/ulx3s/blob/master/doc/MANUAL.md#us2-connector-as-otg-ps2-or-sniffer I have all parts and it works for kbd/mouse
    emard
    @emard
    I see I have to refresh ebay links changed
    Paul Ruiz
    @pnru_gitlab
    @emard did you get RTC working? Uhm.. haven't tried really - sorry. The way I understand the example is that it demonstrates an i2c controller reading a responder. What I need is a module that hides the i2c completely and exposes a retro RTC chip interface, both read and write (a bit like the spi_ide module does). Moving from the example to what I need requires a deep dive into i2c and the RTC chip - I do not want to do that deep dive at this point in time.
    Goran Mahovlic
    @goran-mahovlic
    @MartyMacGyver I have all packets ready, but I need to wait for mouser PO number - I am already waiting for 2 weeks - CrowdSupply promised to get me number until next week - so that is when I will ship all boxes to mouser...
    Lawrie Griffiths
    @lawrie
    @pnru_gitlab If you let me know what interface you want for the RTC, I may look at it, as I have done i2c interfaces on ice40 devices before, and was thinking about doing something similar for the QL.
    emard
    @emard
    @pnru_gitlab in the toplevel it uses the master to read 7 registers but if you want clarity I can move it in a separate module and get you 56 bit vector of BCD coded date/time which changes every second
    BCD is format RTC gives, it doesn't provide count of seconds since epoch, that's a job of CPU to make
    emard
    @emard
    @pnru_gitlab here I have separated mcp7940n.v module that will do reading into 56-bit vector and you can use it as the preliminary version for your unix. I will keep improving mcp module, there are few purity-related details to be fixed. https://github.com/emard/ulx3s-misc/blob/master/examples/rtc/i2c_master/proj/hdl/mcp7940n.v
    Paul Ruiz
    @pnru_gitlab

    @lawrie @emard I don't intend to sound demanding, although probably I do. It is just that with summer behind us I have to focus on the day job as well.

    My plan is to make it similar to Linux on an (retro) PC. The AT used the MC146818 chip and I'm sure that an equivalent is still hiding in the north/south bridges. On Linux you have the hwclock command to copy between the RTC chip and the system clock. See man page here. I will add a /dev/rtc device driver that reads/writes the RTC chip and add a hwclock program. This program can then be put in the /etc/rc boot script.

    The MC146818 is a good model, but I don't like the multiplexed AD bus too much. I like the MM58167 better as a model. All these chips are the same: they provide a bank of byte sized registers with the time, etc. I think the MCP790 is still the same (I'm often surprised how little has changed in 40 years, other than size/speed/bloat increasing by a factor of 1000.)

    Maybe the module interface should be something like:

    module RTC (
      input  wire       clk, // prefer 25 or 125Mhz
    
      // retro CPU interface
      input  wire [5:0] ab,  // 4,5,6, etc. wires all the same to me.
      input  wire [7:0] di,
      output wire [7:0] do,
      input  wire       csn,
      input  wire       wrn,
      input  wire       rdn,
    
      // I2C to RTC chip
      inout wire       scl,
      inout  wire      sda
    );

    How many registers there are, or what data/command is in which register does not really matter to me: that is all easily handed in the /dev/rtc device driver (it will probably read the registers and convert to a string, and vice versa when writing; maybe converting to a time value is even easier).

    I am not sure what the best policy is for syncing between the FPGA and the RTC chip. My first gut feel would be to have a duplicate set of registers in the FPGA and to refresh those autonomously each second (maybe 10x per second). If the duplicate register block had its dirty bit set (i.e. was written to) then the copy would be in the other direction.

    The rc boot script would read /dev/rtc and set the system time from it if it was ahead of system time. If system time is ahead of /dev/rtc it would write the system time to the RTC. To get the ball rolling the user would have to set the right date once. When I get TCP/IP working on the FPGA Cortex it can read out an NTP server and use that as a time base.

    emard
    @emard
    Your retro-pc interface is easiest for me to implement, so OS will then take care of race condition of reading when it changes. For example say you first read 59 minutes and next reading you read incremented hour, so instead of 01:00 you have 01:59, more than hour later :). I don't have to fix in the core, OS will
    emard
    @emard
    is "wire [5:0] ab" the address for RTC's register? there are 32 RTC registers 0x00-0x1F and small general purpose RAM 0x20-0x5F; so [6:0] should be sufficient here
    Paul Ruiz
    @pnru_gitlab
    The MM58167 offers a rollover status bit, but I can live without that. The /dev/rtc device driver can read the registers twice in succession and if the two values are not the same repeat the double read until they are. As the time value on ancient Unix only has 1 second resolution, I don't really need to read the faster registers.
    is "wire [5:0] ab" the address for RTC's register? Yes
    emard
    @emard
    I can make such module you need
    except rollover bit unless MCP datasheet somehow provides it, I didn't study much in detail
    emard
    @emard
    datasheet says the rollover can be avoided by multiple-register read from a single i2c command which I think currently i2c master i borrowed from some forum doesn't have, it does each byte separately hmm
    OK let have something kinda-working first and fix details later :)
    emard
    @emard
    Looking again at your module interface, it seems that I must circular-read all registers and buffer in FPGA registers and be ready to deliver content any time immediately as CPU sets rdn=0? There's not async handshake line to wait for slow i2c to complete the read?
    Paul Ruiz
    @pnru_gitlab
    Yes, there can be a ready signal that stretches the read until data is ready (very similar to DTACK on an 68K). Use with reason, though. As long as ready is low interrupts are not serviced and sdram refresh is paused as well.
    emard
    @emard
    Then I'd rather buffer RTC's 32 bytes than let everything else wait for reading the time.
    Paul Ruiz
    @pnru_gitlab
    It is thinking these type of things through that is so time consuming. At the moment I'm thinking that an autonomous "circular" read is the simplest, maybe using a block read for all registers.
    It is the writing that concerns me: what if a CPU write happens at the same time as the circular read?
    I currently don't have an idea to solve that simply and elegantly.
    emard
    @emard
    I would make priority to write, once module sees write it will buffer its addr/value, halt reads, complete write of requested single byte and continue with circular read
    Maybe we can introduce a simple cache inbetween. So cache would immediately return value. I must also notify unreliable RTC bugs, we can't be really shure that any write has made it until i2c reads it back
    So I'd say first strategy is better: write will halt circular read, make write and circual will resume. CPU must read back to make sure it looks ok after a write
    emard
    @emard
    So, setting alarm or new time will be some CPU intensive, while just reading a time will be really quick
    Paul Ruiz
    @pnru_gitlab
    Sounds a bit complicated, to be honest. How about a ready bit in a status register? It would split each second in three parts. During the first part RDY is true and the CPU can read/write. During the second part RDY is false, but the CPU can still read/write (to deal with the CPU reading RDY just before it switches off). During the third part the I2C controller reads the RTC registers - or, if the registers were modified in the 1st/2nd phase, it writes the registers back. Wouldn't that be much simpler?
    Paul Ruiz
    @pnru_gitlab
    Maybe to make it even more rigid and simple, the state machine should have 4 fixed phases: RDY, RDY grace, write-back, read. The write-back cycle would be disabled if there was no write during phase 1 and 2. This was the I2C controller has 250ms for writing, 250ms for reading and the CPU knows that after reading RDY active, it has at least 250ms to complete its read/write.
    If the controller was using 32 byte block reads/writes, the rollover problem would be solved as well.
    emard
    @emard
    How about just a simple 8-bit interface to i2c master? It will have 4 byte registers to write to make a request and 4 byte to read to get response. It can be reduced to 1 byte to write and 1 byte read if rest of address and directions are set
    emard
    @emard
    // Bit definitions:
    //  31    Read / not write.
    //  30    Repeated Start.  On read cycles setting this bit uses repeated start instad 
    //  29:23 Reserved.
    //  22:16 7-bit I2C address of slave.
    //  15:8  Register Subaddress
    //  7:0   Data to write.  Don't care on read cycles.
    
    //reg [31:0] status;      // I2C status register
    // Bit definitions
    //  31    Busy.  Not ready to accept new control register writes.
    //  30    Address NACK.  Last address cycle resulted in no acknowledge from slave.
    //  29    Data NACK.  Last data write cycle resulted in no acknowledge from slave.
    //  28    Read.  Most recently completed cycle was a read.  Data in bits 7:0 is valid.
    //  27    Overrun.  An attempt was made to write the ctrl_reg while busy.  Cleared
    //        on successful write of ctrl_reg.
    //  26    Initializing - waiting for SDA to go high after module reset
    //  25:8  Reserved.  Tied to zero.
    //  7:0   Read data.  Valid after a read cycle when bit 28 is set.
    Paul Ruiz
    @pnru_gitlab
    It is a good place to start. We can check that with EVMBUG and short programs and see how it goes. Always good to start simple: first single register read/write, then whole bank read/write and finally retro chip emulation.
    emard
    @emard
    I will then make 8-bit interface to i2c master and will test it a bit. For retro chip emulation we need to rethink design to make it properly. MCP has some interrupt flags and may behave specific, for example circular read may unwantedly clear interrupt flags or similar
    Kristin Davidson
    @aphistic
    @lawrie i have been interested in learning and HDL but i've been overwhelmed by the options and i'm kinda in analysis paralysis mode right now. chisel seems neat, i was leaning toward vhdl at one point for a reason i don't remember. verilog seems to be most popular for the risc-v cores i've seen and spinalhdl intrigues me for the same reason chisel does
    emard
    @emard
    @pnru_gitlab here is 8-bit master interface. I haven't tested it very simple by reading seconds and seems ok https://github.com/emard/ulx3s-misc/blob/master/examples/rtc/i2c_master/proj/hdl/i2c_master_8bit.v
    Lawrie Griffiths
    @lawrie
    @aphistic verilog and vhdl are the lower level languages that the others generate. Verilog is directly supported by the open source tool chain but Vhdl is supported via the GHDL Yosys plug in. Only the simplest Risc-v cores (such as picorv32) are written directly in Verilog. The others use one of the higher level languages which generate Verilog. Personally, I mainly use Verilog and SpinalHDL. The reason I learnt SpinalHDL is because Vexriscv is written in it.
    I would recommend starting with Verilog and picorv32.
    Lawrie Griffiths
    @lawrie
    I have had to learn Vhdl as a lot of cores are written in it, but I mainly read it and convert it to Verilog.
    emard
    @emard
    when we are at verilog, I have found on the net several i2c bidirectional bridges. Only one code worked at our board but it works only if compiled by diamond. trellis compiles but doesn't work. Can someone take a look what I have missed: bridge: https://github.com/emard/ulx3s-misc/blob/master/examples/rtc/micropython-mcp7940n/proj/hdl/i2c_bridge.v toplevel usage: https://github.com/emard/ulx3s-misc/blob/master/examples/rtc/micropython-mcp7940n/proj/top/top_i2c_bridge.v
    Kristin Davidson
    @aphistic
    cool, thanks for the insights both of you! I'll start playing around with picorv32 and verilog, then probably move on to spinalhdl once i'm more comfortable with verilog
    since it'll be a month or so before my ulx3s gets here i'll have to start with the tinyfpga bx's i have sitting around :)
    Lawrie Griffiths
    @lawrie
    I did quite a few projects on the TinyFPGA BX using picosoc. The first one to start with is the simple one in the examples - https://github.com/tinyfpga/TinyFPGA-BX/tree/master/examples/picosoc
    Paul Ruiz
    @pnru_gitlab

    @emard I integrated your i2c module into the cortex (see https://gitlab.com/pnru/ulx3s-misc/-/blob/master/tmp/sys.v). It does not seem to work for me, but maybe I'm using it wrong. I also - and I really should not have - went down the rabbit hole and wrote an I2C master from scratch (see https://gitlab.com/pnru/ulx3s-misc/-/blob/master/tmp/i2c.v). It also does not seem to work for me.

    When I look at the wave forms in Icarus/GTKWave I think both bits of code are producing very similar signals that should work (at least in my current understanding or I2C and the MCP7940). Your code is more careful to debounce the SCL and SDA signals. It also seems to have an I2C bus reset that I don't have (Start followed by Stop, with no clocks in between.) A 3rd difference is that I'm running SCL at ~400KHz and you are is using ~1Mhz

    I really need to get back to real work, but if someone wants to take a look at and do a code or GTKWave review over the next days, I'd be grateful.

    If all else fails, I will route SCL and SDA to the side headers and attach a logic analyser, so that I can see what the RTC chip actually responds.
    emard
    @emard
    Doesn't work mean you get 0xFF or 0x00 values reading all registers? I'll check pullup/pulldown sensitivity maybe reason is simple
    emard
    @emard
    for me it works for any gpdi_scl/sda PULLMODE=UP, DOWN, or NONE so it's not pull setting. I can prepare a bitstream and micropython to ulx3s-bin example that initializes the clock setting time from NTP
    emard
    @emard
    https://github.com/emard/ulx3s-bin/tree/master/esp32/micropython/rtc can you try this RTC esp32 example for NTP setting? >>> rtcdemo.mcp.time should advance seconds