Jump to content
  • Sky
  • Blueberry
  • Slate
  • Blackcurrant
  • Watermelon
  • Strawberry
  • Orange
  • Banana
  • Apple
  • Emerald
  • Chocolate
  • Charcoal

Search the Community

Showing results for tags 'oc2'.

More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


  • OpenComputers
    • Announcements
    • Feedback
    • IRC
  • Code Central
    • Support
    • Showcase
    • Tutorials
  • Addons & More
    • Addons Mods
    • Architectures
    • OpenEngineering Task Force
  • General
    • Lounge
    • Forum Games
    • Showcase
    • Servers
  • Archives
    • Public Archives

Find results in...

Find results that contain...

Date Created

  • Start


Last Updated

  • Start


Filter by number of...


  • Start





Website URL








Fediverse ID



Found 2 results

  1. This is something that I'm scratching my head over. It would be great if this were written in C (and if I had a dollar for every time I thought that... I think I'm up to about $5 now?), but alas, it isn't, and thus multiple return values are very much out of the question. Having a think about it, it would make sense if the bus ran at 1MHz. The Z80 currently runs at 2MHz, and all memory accesses on the Z80 tend to take a minimum of 3 cycles (in reality it's more like 2 cycles followed by a DRAM refresh but we'll just skip on that and assume the whole window is available for it). The MIPS3 core I'm working on also runs at 2MHz. I would like to be able to clock that at a higher speed than the main bus, but in order for that to work, the bus needs an API for it. Easy case: Only one CPU on the bus public int getTime(int cpuid); public int ensureTime(int cpuid, int currentTick); public int eatCycles(int cpuid, int startTick, int lengthInTicks); Reason for providing cpuid anyway is so that the same API can be used for a multi-CPU setup.Reason for returning an int in ensureTime is to get the correct point in time. How to access the bus (a proposal): int targetBusTime = this.currentTimeSliceBusTicks - (this.cycleBudget/this.clockMultiplier); int actualBusTime = memory.ensureTime(this.cpuid, targetBusTime); // do reads and writes here - eatCycles is called by the bus components int endBusTime = memory.getTime(this.cpuid); this.cycleBudget = this.currentTimeSliceCpuTicks - endBusTime; Of course, a more advanced CPU implementation would track this as a separate variable, and dispatch reads and writes in a manner that avoids stalling the CPU where possible.In a system which ignores the cpuid, these can be implemented like so: private int busTime = 0; private int onTickStart_ResetBusTime() { this.busTime = 0; } public int getTime(int cpuid) { return this.busTime; } public int ensureTime(int cpuid, int currentTick) { if(this.busTime < currentTick) { this.busTime = currentTick; } return this.busTime; } public int eatCycles(int cpuid, int startTick, int lengthInTicks) { ensureTime(startTick); this.busTime += lengthInTicks; return this.busTime; } Hard case: More than one CPU on the busOh yeah, the thing that makes this more fun? By "CPU", anything which does DMA could be classified as a "CPU". If all CPUs execute in parallel, then the one-CPU approach can work just fine. Otherwise, that bus is going to suffer horribly. Ultimately you need to track each CPU's busTime in an array (i.e. private int[] busArray;), and implement what is basically a memory allocator minus the memory. You'll basically need to track various windows into the bus in a sorted manner. I'd say a bitfield implemented in terms of ints would be the most suitable approach. As for ensuring that no one CPU can hog the bus the whole time, well, you could possibly inject a few windows into the bus on the bus controller. Or you could just punch anyone who decides to use a 6502 on a multiprocessor system. One more thing, I've just noticed an issue with this "time travel" approach: There is no guarantee that I/O will be executed in the correct order or RAM updated in the correct order between CPUs. Easy solution for hard case: Timeslicing Each CPU gets given a reasonably short timeslice of the bus. Possibly two timeslices per tick. Really easy solution for hard case: Don't even bother with accuracy Just run each CPU in its own thread and completely ignore this proposal. Simple.
  2. Draft 1 D1: 2016-08-05T02:45:39+00:00 $ date -u -Iseconds ----There are two address spaces for all components: the config space, and the main I/O space. Every component has a VID (virtual ID) and that is how components are addressed. Every VID should be physically settable to any 8-bit value on each component. Any component with a VID set to 0xFF is rendered inaccessible by any methods that address by VID. Every component also has a PID (physical ID) which indicates the physical location of this component on a given bus master. The config space is read-only. Everything in the config space is readable by any bit width. CONFIG SPACE This bus is little-endian. These fields are compulsory, and every component needs to read at least the bottom 3 address bits: 0x00[4]: 4-byte type ID. Forms a 4-char ASCII string. 0x04[1]: Bus PID. 0x05[1]: Bus master VID. 0xFF if using the root bus master. 0x06[1]: Bus PID with all bits inverted. 0x07[1]: Bus master VID with all bits inverted. These two fields are optional, and there is no requirement for bit 3 to be read:0x08[4]: 4-byte extension ID #1. 0x0C[4]: 4-byte extension ID #2. Components are allowed to go further than this.Open bus is 0xFFFFFFFF, because that's what us low-level weirdos tend to expect. This applies to all busses. Because of this, if you have a type ID of 0xFFFFFFFF, that VID has no component using it. The root bus master (it'll be on your motherboard) is of course an exception to a lot of these rules: VID is always 0xFF and it is completely unconfigurable. PID is 0xFF too. So is the bus master VID. If the ID is 0xFFFFFFFF, then this bus master cannot be reconfigured, but there's DEFINITELY a bus master here. Basically, if you have a "dumb" bus master, the config space will be open bus, which also means that a bus conflict check will fail. Components should avoid using any I/O ports outside of 0x00-0x7F in its main I/O bus for ease of addressability with a lot of CPUs.Some components will have standard VID slots. Conflicts should be avoided where possible. Proposed standard slots: 0x00: Various BIOS EEPROMs would probably end up using this. 0xC0: MIPS BIOS EEPROM. 0xDB: Serial debug interface. ID is "Dbg0". Write to 0x00 to output byte, read from 0x00 to input byte, -1 will be returned if no byte is available, bus is actually 32 bits wide, but can be accessed by byte, reads from 0x01-0x03 are buffered. For an example, here's how things would be addressed on MIPS:0x0+++++++: User virtual memory space 0x800xxxxx: Cached RAM (bit mask is for 1MB) 0xA00xxxxx: Uncached RAM (bit mask is for 1MB) 0xBEvv00rr: Uncached Config space for VID=v, address=r 0xBFvvrrrr: Uncached Main I/O space for VID=v, address=r 0xC+++++++: Kernel virtual memory space CODE SAMPLES:These are in MIPS assembly. There is no op reordering, but I have decided to insert NOPs in delay slots just for the sake of readability. I have also decided to use the LA ("Load Address") pseudo-op as a load-immediate so things are a bit more obvious. To clarify: LA loads the 32-bit value you see there DIRECTLY - it does not do a memory load. (It's also reasonably likely to use 2 real ops, although I think there's really only one place here where it actually does.) I have tried to avoid MIPSisms here. Component presence detection: (ID in $a0, $v0 returns nonzero if there is a component) LA $t0, 0xBE000000 ANDI $t1, $a0, 0x00FF SLL $t1, $t1, 16 ORI $t0, $t0, $t1 LW $t1, 0x00($t0) NOP ADDIU $v0, $v0, 1 // convert 0xFFFFFFFF -> 0 JR $ra NOP Bus conflict detection: (ID in $a0, $v0 returns nonzero if there is a conflict, note this will trigger if there is no component) LA $t0, 0xBE000000 ANDI $t1, $a0, 0x00FF SLL $t1, $t1, 16 ORI $t0, $t0, $t1 LH $t1, 0x04($t0) // LH is a signed load, thus you get a sign extension LH $t2, 0x06($t0) NOP XOR $v0, $t1, $t2 ADDIU $v0, $v0, 1 // convert 0xFFFFFFFF -> 0, or 0 -> 1 JR $ra NOP Fun thing, if there is no component here, you will get 1 in $v0, so you can do this: MOVE $a0, $s0 J detect_bus_conflict NOP LA $t0, 1 BEQ $v0, $t0, _vid_does_not_exist NOP BNEZ $v0, _vid_has_bus_conflict NOP Finally, how to spew "Hello World!" down every Dbg0 device (as opposed to just assuming that it's at 0xDB): LA $t0, 0xBE000000 LA $t1, 0x00010000 LA $t2, 255 LA $t3, 'Dbg0' _loop_find: // Detect Dbg0 component LW $t4, 0x00($t0) NOP BNE $t4, $t3, _loop_find_continue NOP // // Print hello message // LA $t6, str_hello LA $t5, 0x01000000 LB $t7, 0($t6) // Preload first byte ADDU $t5, $t5, $t0 // 0xBFxxxxxx address // Actual print loop _loop_hello: SB $t7, 0($t5) ADDIU $t6, $t6, 1 LB $t7, 0($t6) NOP BNEZ $t7, _loop_hello NOP // Advance loop _loop_find_continue: ADDIU $t2, $t2, -1 ADDU $t0, $t0, $t1 BNEZ $t2, _loop_find NOP // Return JR $ra NOP // Read-only data str_hello: .asciiz "Hello World!\n"
  • Create New...

Important Information

By using this site, you agree to our Terms of Use and Privacy Policy.