Last visit was: Sat Jul 31, 2021 5:57 am
It is currently Sat Jul 31, 2021 5:57 am



 [ 87 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6
 CS01 
Author Message

Joined: Sat Feb 02, 2013 9:40 am
Posts: 1442
Location: Canada
Got the Monitor program running in the machine level. Getting the OS to recognize arguments from calls made from machine level was fun. The hardware now tracks the previous level for argument switches instead of just using the user level. So, ecalls can be performed from either user or machine levels and will still work.
Got Tiny Basic working again! Now to add some primitives to it that allocate objects so that I can work on the garbage collector. Hmm, doesn’t work as well as I thought. Seems to work in direct mode, but not with programs.
Attachment:
TinyBasic02.png

The Sleep() function doesn’t work yet. For some reason calling Sleep() causes the operating system to loop around endlessly. It’s probably a bad pointer somewhere.


You do not have the required permissions to view the files attached to this post.

_________________
Robert Finch http://www.finitron.ca


Mon Sep 07, 2020 4:19 am WWW

Joined: Wed Jan 09, 2013 6:54 pm
Posts: 1626
A milestone! Well done.


Mon Sep 07, 2020 8:09 am

Joined: Sat Feb 02, 2013 9:40 am
Posts: 1442
Location: Canada
Constantly debugging and improving the system. Finally got the virtual memory map dump function of the monitor working. For the longest time it would only dump the memory map of app #0 regardless of what was requested.
Switched the system to use an eight-bit task id. Implemented a ready queue(s) using hardware.
Changed the timeout component to queue task id’s that have zeroed out in a hardware queue. This allows a slightly simpler implementation of the timeout code in the scheduler. Previously a bit mask of timed out tasks was used and it was a bit of bit fiddling to convert to a task id.
Still working on getting interrupt driven scheduling to work properly. It’s tricky because the scheduler code runs with access to OS variables at the machine level. If a program is running in user mode and a scheduler interrupt occurs that’s okay. But If the OS is already running and a scheduler interrupt occurs that presents an issue because the OS isn’t re-entrant. At the moment if the OS is already running and receives a scheduler interrupt, then the interrupt just sets a flag and returns immediately. Back in the OS at the exit point of the OS routines a check is made to see if the flag is set. The scheduler is then called if needed.

_________________
Robert Finch http://www.finitron.ca


Wed Sep 09, 2020 3:37 am WWW

Joined: Sat Feb 02, 2013 9:40 am
Posts: 1442
Location: Canada
Switched the bitmap used to track tasks waiting for messages to a linked list of waiters. The linked list is faster and more flexible. Interrupts are turned off while lists are being manipulated so it’s important code is done as fast as possible.
Debugging can be a bit of a challenge. Tiny Basic isn't storing program text properly. I’m trying to locate where in memory the string “Hello World!” occurs as that’s what the Tiny Basic program prints. The goal is to locate the line of text in memory because lines of text aren’t being placed properly. So, I wrote a little string search routine that searches all of memory. It finds the string in the Monitor’s input buffer and in the serial receive buffer, but nowhere else.
I’ve tracked the miscreant code down to a load or store operation that’s failing. What ends up in memory is ‘1A000064’ and it’s supposed to be ‘00000064’. The ldbu or stb fails in the following code:
Code:
InsertLine:
  mov   $t2,$a0
  mov   $t3,$a1
   beqz   $a2,.done          ; zero length? Probably a SW error
.0001:
   ldbu   $t1,[$a1]            ; get from source text
   stb      $t1,[$a0]            ; store to insertion point
   ldi   $a0,#'L'
   call  Putch
   mov   $a0,$t1
   call  PutHexByte
   add      $a1,$a1,#1         ; increment pointers
   add      $a0,$a0,#1
   sub      $a2,$a2,#1         ; decrement length
   bgtz   $a2,.0001
.done:
  ldt   $a0,1[$t2]
  call  PutHexWord
  ldi   $a0,#':'
  call  Putch
  ldt   $a0,1[$t3]
  call  PutHexWord
  ldi   $a0,#':'
  call  Putch
   ret

It's looking like an obscure hardware issue of some sort. So, I'm going to try more timing constraints in build.

_________________
Robert Finch http://www.finitron.ca


Thu Sep 10, 2020 3:09 am WWW

Joined: Sat Feb 02, 2013 9:40 am
Posts: 1442
Location: Canada
And the Tiny Basic issue was hardware not providing enough clock cycles for the paging ram to present it’s value only when two bus cycles were required in order to support an unaligned access. Single bus cycle accesses worked fine. It took me the longest time to find what I thought was a software issue. The operating system always uses aligned memory accesses for performance. So it didn’t show up there.
Tiny Basic is mostly working in run mode too now as well as direct mode.

_________________
Robert Finch http://www.finitron.ca


Fri Sep 11, 2020 3:46 am WWW

Joined: Sat Feb 02, 2013 9:40 am
Posts: 1442
Location: Canada
The system has an undead queue now for tasks that are finished (ExitTask or KillTask called). The undead queue is checked by a finalizer task which causes the task’s finalizer code to be run if present, otherwise the task is marked dead making it suitable for garbage collection.

Tasks are dropping out of the ready queue when they shouldn’t be. I’ve made the scheduling code operation as simple as I could. It pops a task off a ready queue, then pushes it back onto the ready queue. Popping and pushing the task causes the tasks in a queue to process in a round-robin fashion.

The system currently has 24k ROM. Tiny Basic is about 8kB and the OS uses the remaining 16kB.

_________________
Robert Finch http://www.finitron.ca


Sat Sep 12, 2020 3:58 am WWW

Joined: Sat Feb 02, 2013 9:40 am
Posts: 1442
Location: Canada
Updated the code to correspond to the latest register usage conventions. Had to change a lot of code removing references to $v0, $v1. In the latest usage convention $a0, $a1 are used both as the first two subroutine arguments and two return values.
Well, it’s busted good now. At least the startup menu still displays.

I’ve been moving operating systems objects from static storage allocations to dynamically allocated storage. There was a lot of potentially wasted storage space because static storage must consider worst case requirements. The static storage footprint is much smaller now. Globals are less than 8kB.
The system memory allocator allocates in 1kB blocks so if there are small objects to be allocated (messages and mailboxes) they are grouped together in a 1kB block. I had to come up with a fast and simple way to compute the mailbox address given a handle. The OS only passes out handles so that app code can’t discover where objects are.

Pre-emptive task switching doesn’t work yet. For some reason the IRQ code thinks the operating system is running all the time. It never seems to clear the ‘I’m operating’ semaphore. This has me stumped at the moment because there is only one entry and one exit point to the operating system. On entry a flag is set, then on exit the flag is cleared.
Code:
;------------------------------------------------------------------------------
; Operating system call dispatcher.
; On entry machine registers are selected.
;------------------------------------------------------------------------------
  align 16
OSCALL:
  mEI
  csrrs $x0,#$7C1,#1    ; set OS running semaphore
   csrrs   $t1,#$7C0,#2      ; select user regs for Rs1      
   mov      $a0,$a0               ; move user to machine
   mov      $a1,$a1
   mov      $a2,$a2
   mov      $a3,$a3
   mov      $a4,$a4
   mov      $a5,$a5
   csrrc   $x0,#$7C0,#15      ; get back machine registers for all
;OSCALL2:
   and      $a0,$a0,#63
   add      $a0,$a0,$a0     ; shift left one bit
   ldwu  $t0,OSCallTbl[$a0]
   or    $t0,$t0,#$FFFC0000
   beqz  $t0,OSExit
   jmp      [$t0]

;------------------------------------------------------------------------------
; Exit from the operating system. All operating system routines use this
; fragment of code to return. Return values are transferred to the
; previously active register set.
;------------------------------------------------------------------------------

OSExit:
   csrrs   $x0,#$7C0,#1            ; select user for destination
   mov      $a1,$a1                     ; move return values to user registers
   mov      $a0,$a0
   csrrc $x0,#$7C1,#1        ; clear OS running semaphore
   jmp   ERETx2

In the interrupt driven scheduler the code looks like:
Code:
  align 16
FMTK_SchedulerIRQ:
   ; See if the OS was interrupted.
   csrrw $a0,#$7C1,$x0   ; Is the OS running?
   and   $a0,$a0,#1
   beqz  $a0,.noOS
   ret                   ; refuse to continue this function
.noOS:
… schedule code

The scheduler code never runs so the pre-emptive switches don’t happen. More debugging required.

_________________
Robert Finch http://www.finitron.ca


Sun Sep 13, 2020 3:38 am WWW

Joined: Sat Feb 02, 2013 9:40 am
Posts: 1442
Location: Canada
The OS running all the time was due to several sources of interrupts that were active all the time because they weren’t serviced. An interrupt pending bit (msip) that didn’t have a defined value on reset caused a permanently on interrupt. The toolset assumed a reset value of 1 meaning the interrupt was always pending since it isn’t yet processed by the code.

The device function tables are getting zeroed out somehow. This causes the system to hang since it doesn’t have access to any I/O devices. So, for now I have the OS dynamically reinitialize the device function tables if there’s a zero found for the function address. That at least gets me output for diagnostics.

The wait for interrupt (WFI) instruction doesn’t work. It stops the clock, but the clock doesn’t restart again. It should because an active interrupt signal is gated onto the clock gate. If an interrupt is active, then the clock should pass. WFI sets a flag in the EX state, then clears the same flag in the WB state. The processor is then halted in the EX state. It only needs one clock to get through in order to operate normally.

_________________
Robert Finch http://www.finitron.ca


Mon Sep 14, 2020 3:36 am WWW

Joined: Sat Feb 02, 2013 9:40 am
Posts: 1442
Location: Canada
Working on the register sets today. Switched from distributed ram registers to block ram registers. This makes more register sets available.

Getting closer to getting multi-tasking working. The system runs and displays part of the startup message then hangs. I checked and it’s actually switching tasks to the idle task. When the idle task runs, its job at the moment is to search for tasks that have fallen out of the ready queue. The OS seems to select the idle task all the time to run, so I checked and it should be selecting other tasks but doesn’t.

_________________
Robert Finch http://www.finitron.ca


Tue Sep 15, 2020 3:56 am WWW

Joined: Sat Feb 02, 2013 9:40 am
Posts: 1442
Location: Canada
The system was plagued with ‘illegal instruction’ exceptions, it’s a wonder it worked at all. The operating mode of the task wasn’t being saved and restored properly. It’s another bit of context data that needs to be saved and restored. An mret instruction would return to the wrong operating mode which sometimes caused an ‘illegal instruction’ exception as code tried to execute privileged instructions in user mode. When really the return was supposed to be to machine mode.

Created a “thingy”, kind of a gateway trampoline, to allow running OS code from a user task. It simply takes a pointer to code and runs it at the OS privilege level. So, it jumps to the OS which then jumps back to the user code. This is restricted to tasks deemed to be part of the OS. The issue was trying to do too much with just two operating modes. All tasks run at the user mode level now for simplicity’s sake.

Added an interrupt enable delay feature to the via6522 component. It can now be specified to delay the enabling of interrupts for a specified number of clock cycles after the interrupt enable register is set. The issue is being able to continue to run code after the code for enabling interrupts. For example, the processor needs a few cycles to be able to execute the mret after signaling that interrupts need to be enabled.
Code:
OSExit:
   csrrs   $x0,#CSR_REGSET,#1      ; get register sets
   mov      $a1,$a1                     ; move return values to user registers
   mov      $a0,$a0
   csrrc $x0,#CSR_REGSET,#15 ; restore register set selection
   csrrc $x0,#$7C1,#1        ; clear OS running semaphore
   ldi      $t0,#$14000180         ; enable timer3 interrupts after 20 cycles
   stt      $t0,VIA_IER+VIA
   mret

_________________
Robert Finch http://www.finitron.ca


Wed Sep 16, 2020 4:23 am WWW

Joined: Sat Feb 02, 2013 9:40 am
Posts: 1442
Location: Canada
Still working to get multi-tasking working properly. It’s a lot of fun. I had interrupt enable / disable code all over the place then I realized that the OS could run with interrupts enabled except for the time-slice interrupt which accesses OS vars. So, now the OS disables only the time-slice interrupt on entry and re-enables it on exit.

Having a lot of fun dealing with the different object type id’s in the system. I mixed it up a couple of times. There’s the app id (application id) unique to every app. Then there’s the memory map id, identifying the memory map in use, and the task id. There’s also handles for mailboxes and messages. While there are id’s for different system objects there are also numbers for them as well. The two are not the same. The id or handle is an address hash for the object, while the number is an ordinal.

_________________
Robert Finch http://www.finitron.ca


Fri Sep 18, 2020 6:08 am WWW

Joined: Sat Feb 02, 2013 9:40 am
Posts: 1442
Location: Canada
Found a lingering error in the rtl code for the processor. It turns out that address bits 11 to 18 were being used to index the page ram, and it should have been address bits 10 to 17. This caused the wrong pages to be read / written but only while in user mode.

Task switching works a little better now after numerous software updates. Currently the HasFocus() function is setup to return always true. That causes output from different tasks to be intermixed as processing gets part-way through a display for one task then switches to another. This was done to get some output otherwise nothing is displayed. There is still an issue with selecting focus for the input and output. The focus is supposed to be selectable from a CTRL-T keyboard press, but that doesn’t seem to work yet.
Attachment:
Startup.png

All the arrows are the command prompt which keeps repeating. Somehow a loop forms while running that causes a string of ‘>’ to be output. The system then hangs after task switching several times.

I’ve just been debugging software using the logic analyzer of the toolset, rather than building a software emulator. It’s taking only about 4 minutes to rebuild the system for the FPGA due to the use of a small FPGA. So, the turn-around time for bug fixes is short.


You do not have the required permissions to view the files attached to this post.

_________________
Robert Finch http://www.finitron.ca


Mon Sep 21, 2020 3:47 am WWW
 [ 87 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6

Who is online

Users browsing this forum: CCBot, SemrushBot and 0 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Jump to:  
Powered by phpBB® Forum Software © phpBB Group
Designed by ST Software